[关闭]
@2368860385 2018-08-31T08:44:44.000000Z 字数 4503 阅读 552

六校联考day2——2018.8.30

比赛总结


预计100 + 100 + 30+(写了2^n次方搜索,居然过了大样例,对于有些数据可以过)
实际70 + 50 + 50

T1

想O(n)的算法没想出,于是想了一个复杂度比nlogn小些的复杂度。
一个点作为贡献,且作为右端点,那么只要在前面找到一个大于它的数,且这个数最远就可以了。
对于前面两个可能作为左端点的数x,y,假设x在前,那么如果y < x,y就不会作为左端点。
如果当前的右端点数z,若z < y那么x和y都可以作为左端点,而x在y前面,它的区间就长,所以x更优。
如果z > y && z < x,x可以作为左端点。
(如果z > x,那么x,y都不可以作为左端点。)
所以用一个数组记录到当前位置上升的数,在这里面二分出第一个大于这个数的数,并找到这个位置;如果当前数大于数组中最大的数,那么加入当前数,continue。
之后要把原数组反过来在做一遍,一开始忘了,过不了大样例,小样例对拍没发现问题,居然以为大样例错了。。。后来用n^2的暴力跑了70多秒(开O2的29左右),跑出答案,发现大样例没错。于是又继续调,发现了这个问题。
T1做完时9点左右。最后特判了一个n<=1000的数据,把暴力程序复制过来了。然而程序这样写的。

  1. int main() {
  2. int n = read();
  3. if (n <= 1000) { solve1(n); return 0; }
  4. for (int i=1; i<=n; ++i) a[i] = read();

发现没读入,最后用文件试了一下大样例,没试小样例。
以后所有样例都用文件试一遍。
还有一个低级错误,开始想1e6的数据很大,于是写了fread,但是为了调试,先注释了,最后也没有上。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cctype>
  6. #include<cmath>
  7. #include<set>
  8. #include<map>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long LL;
  13. // char buf[100000], *p1, *p2;
  14. // #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
  15. // inline int read() {
  16. // int x = 0, f = 1; char ch = nc(); for (; !isdigit(ch); ch=nc()) if (ch=='-') f = -1;
  17. // for (; isdigit(ch); ch=nc()) x = x * 10 + ch - '0'; return x * f;
  18. // }
  19. inline int read() {
  20. int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch=getchar()) if (ch=='-') f = -1;
  21. for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; return x * f;
  22. }
  23. const int N = 1000010;
  24. int a[N], q[N], s[N];
  25. void solve1(int n) {
  26. LL Ans = 0;
  27. for (int i=1; i<=n; ++i) {
  28. for (int j=i; j<=n; ++j) {
  29. int t = min(a[i], a[j]);
  30. Ans = max(Ans, 1ll * (j - i + 1) * t);
  31. }
  32. }
  33. cout << Ans;
  34. }
  35. LL solve2(int n) {
  36. int Top = 1;
  37. LL Ans = 0;
  38. q[1] = a[1], s[1] = 1;
  39. for (int i=2; i<=n; ++i) {
  40. if (a[i] > q[Top]) {
  41. q[++Top] = a[i], s[Top] = i;
  42. continue;
  43. }
  44. int L = 1, R = Top, pos = -1, mid;
  45. while (L <= R) {
  46. mid = (L + R) >> 1;
  47. if (q[mid] >= a[i]) pos = s[mid], R = mid - 1;
  48. else L = mid + 1;
  49. }
  50. Ans = max(Ans, 1ll * (i - pos + 1) * a[i]);
  51. }
  52. return Ans;
  53. }
  54. int main() {
  55. // freopen("1.txt","r",stdin);
  56. freopen("w.in","r",stdin);
  57. freopen("w.out","w",stdout);
  58. int n = read();
  59. LL Ans = 0;
  60. for (int i=1; i<=n; ++i) a[i] = read(), Ans = max(Ans, (LL)a[i]);
  61. Ans = max(Ans, solve2(n));
  62. for (int i=1; i<=n; ++i) s[i] = a[i];
  63. for (int i=1; i<=n; ++i) a[i] = s[n - i + 1];
  64. Ans = max(Ans, solve2(n));
  65. cout << Ans;
  66. return 0;
  67. }

T2

开始半小时读题的时候,想到了一个做法,9点写完T1,然后来写T2,20分钟左右写完,过了大样例。
然后居然又没取模!!!少了50分。

摘自题解:
这种操作是一定做了比没做优的。




所有变化后一定更优。

思路:发现两个数进行完操作后,
在都有1的位上不变,
在一个是1一个是0的位上,所有的1都到了一个数上。
001101010
010101000
变成:
000101000
011101010
发现只不过是将一个数的某些位上的1给了另一个数。所以将每个数拆成很多个1,可以计算出每一位一共有多少个1,每次一个数不停的取1。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cctype>
  6. #include<cmath>
  7. #include<set>
  8. #include<map>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long LL;
  13. inline int read() {
  14. int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch=getchar()) if (ch=='-') f = -1;
  15. for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; return x * f;
  16. }
  17. const int mod = 998244353;
  18. const int N = 200010;
  19. int a[N], cnt[N];
  20. int main() {
  21. // freopen("1.txt","r",stdin);
  22. freopen("s.in","r",stdin);
  23. freopen("s.out","w",stdout);
  24. int n = read(), mx = 0;
  25. for (int i=1; i<=n; ++i) {
  26. a[i] = read();
  27. for (int j=0; (1<<j)<=a[i]; ++j) {
  28. if ((1 << j) & a[i]) cnt[j] ++, mx = max(mx, j);
  29. }
  30. }
  31. LL Ans = 0;
  32. while (true) {
  33. LL x = 0, flag = 0;
  34. for (int i=0; i<=mx; ++i) {
  35. if (cnt[i]) x |= (1 << i), cnt[i] --, flag = 1;
  36. }
  37. if (!flag) break;
  38. Ans = (Ans + 1ll * x * x) % mod;
  39. }
  40. cout << Ans % mod;
  41. return 0;
  42. }

T3

暴力写了很长时间。。。
然后感觉好像轮廓线dp,记录上两行的状态,转移,然后发现空间开不下,时间也不对。空间
正解:其实不是轮廓线dp,直接状压dp,发现很多状态是一定不合法的。比如001100,001010这种就不合法,去掉这种,发现只剩下了406个,然后状态就很少了,可以转移了。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cctype>
  6. #include<cmath>
  7. #include<set>
  8. #include<map>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long LL;
  13. inline int read() {
  14. int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch=getchar()) if (ch=='-') f = -1;
  15. for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; return x * f;
  16. }
  17. const int mod = 1e9 + 7;
  18. int ban[16], f[16][500][500];
  19. vector <int> sta;
  20. inline bool isLine(int a) {
  21. return !((a & (a << 1)) || (a & (a << 2)));
  22. }
  23. inline bool isTwoLines(int a,int b) {
  24. return !((a & b) || (a & (b << 1)) || (a & (b >> 1)));
  25. }
  26. inline bool isThreeLines(int a,int b,int c) {
  27. return !(a & c) && isTwoLines(b, c);
  28. }
  29. int main() {
  30. int n = read(), m = read(), k = read();
  31. for (int i=1; i<=k; ++i) {
  32. int x = read(), y = read();
  33. ban[x] |= (1 << (y - 1));
  34. }
  35. for (int i=0,lim=(1<<m)-1; i<=lim; ++i)
  36. if (isLine(i)) sta.push_back(i);
  37. int maxS = sta.size();
  38. for (int i=0; i<maxS; ++i)
  39. f[0][i][0] = 1;
  40. LL ans = 0;
  41. for (int i=1; i<=n; ++i) {
  42. for (int a=0; a<maxS; ++a) { // 当前行的状态
  43. if (sta[a] & ban[i]) continue;
  44. for (int b=0,lim=(i<=1?1:maxS); b<lim; ++b) { // i - 1行
  45. if ((sta[b] & ban[i - 1]) || !isTwoLines(sta[a], sta[b])) continue;
  46. for (int c=0,lim2=(i<=2?1:maxS); c<lim2; ++c) { // i - 2行
  47. if ((sta[c] & ban[i - 2]) || !isThreeLines(sta[a], sta[b], sta[c])) continue;
  48. int &ts = f[i][a][b];
  49. f[i][a][b] = (f[i][a][b] + f[i - 1][b][c]) % mod;
  50. ts = f[i][a][b];
  51. }
  52. if (i == n) ans = (ans + f[i][a][b]) % mod;
  53. }
  54. }
  55. }
  56. cout << ans;
  57. return 0;
  58. }

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注