[关闭]
@2368860385 2020-11-07T03:10:01.000000Z 字数 3695 阅读 181

1040——Codeforces Round #507 (Div. 2, based on Olympiad of Metropolises)

codeforces

https://codeforces.com/contest/1040

2018.9.6凌晨实时参加
2018.9.6整理


比赛经过

记一下比赛经过。0:35开始,10点半左右搬到机房被子,然后写了一下“互不侵犯”,然后得了80分,11点半了,有点困,于是躺下休息一会,想休息一个小时或者40分钟左右,然后一觉睡到了1点半,起来还有一个小时。还有点困。先写了A,一遍过了,然后B调了好几个错误,过了,然后见C之后几个人过,D又是交互题,还有没写过,于是看E(E比C过的人还多),还有17分钟,没读懂题已经结束了。

A

模拟
维护两个指针,不同了直接输出-1,如果一个可以买,那么让他跟另一个样,如果两个都可以买,买便宜的。特判一下n为奇数,枚举到中间的情况。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cctype>
  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. int w[1000];
  18. int main () {
  19. int n = read(), a = read(), b = read();
  20. for (int i=1; i<=n; ++i) w[i] = read();
  21. LL Ans = 0;
  22. for (int l=1,r=n; l<=r; r--,l++) {
  23. if (l == r) {
  24. if (w[l] == 2) Ans += min(a, b);
  25. }
  26. else if (w[l] == w[r]) {
  27. if (w[l] == 2 && l!=r) Ans += min(a, b) * 2;
  28. } else {
  29. if (w[l] == 2 && w[r] == 1) Ans += b;
  30. else if (w[l] == 2 && w[r] == 0) Ans += a;
  31. else if (w[r] == 2 && w[l] == 1) Ans += b;
  32. else if (w[r] == 2 && w[l] == 0) Ans += a;
  33. else { puts("-1"); return 0; }
  34. }
  35. }
  36. cout << Ans;
  37. return 0;
  38. }

B

模拟。
每次优先选最长,即k+k+1,假设选t个,剩下的如果大于等于k+1,那么就再选一个k+1,否则,t--,然后选两个在k+1大于k+1的。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cctype>
  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. int main () {
  18. int n = read(), k = read();
  19. if (k >= n) {
  20. puts("1");
  21. puts("1"); return 0;
  22. }
  23. if (k + k + 1 >= n) {
  24. puts("1");
  25. cout << n / 2 + 1;
  26. return 0;
  27. }
  28. int f = 0, e = 0;
  29. int c = n / (k + k + 1), t = (n % (k + k + 1));
  30. if (t >= k + 1) f = t;
  31. else if (t == 0) t = 0;
  32. else t += (k + k + 1), c --, f = k + 1, e = t - f;
  33. //cout << c << " " << f << " " << e; return 0;
  34. int cnt = c + (f?1:0) + (e?1:0);
  35. cout << cnt << "\n";
  36. int now = -(k);
  37. if (f) now = f - (k), cout << now << " ";
  38. for (int i=1; i<=c; ++i) {
  39. now += k;
  40. now += (k + 1);
  41. printf("%d ", now);
  42. }
  43. if (e) {
  44. now +=k;
  45. now += (k + 1);
  46. cout << now;
  47. }
  48. return 0;
  49. }

E

题意:
一张图,n个点,m条边,然后每个点有个权值x,x<=1e18。如果一条边是安全的,那么这条边的两个端点的权值不能一样,给定的图所有的边都是安全的。现在有一个病毒,病毒有一个权值(不知道这个权值),病毒可以入侵任意的点,入侵后的权值为(x^原来的权值)。
(S,x)表示病毒的权值为x,它只入侵了点集S中的点,然后整张图的边都是安全的。
求出所有的(S,x)。

题意二:

一张图,n个点,m条边,然后每个点有个权值x,x<=1e18。如果一条边的两个端点不一样,那么这条边是安全的,开始时所有边都是安全的。现在有一个病毒y,病毒可以入侵任意的点,入侵一个点后的权值为(y^x)。
(S,y)表示病毒的权值为y,它只入侵了点集S中的点,然后整张图的边都是安全的。求出所有的(S,x)。

设一条的边的两个端点为u,v,病毒为x。
如果u,v同时异或了x,那么他们还是安全的。
不安全的情况当且仅当,u^x=v。如果存在这样的x,那么一定知道v^x=u(由异或的性质a^x=b,b^x=a,a^b=x),那么这两个点要么同时异或x,要么都不异或x。所以可以把这两个点缩成一个。
所以原图中设每条边的权值为u^v(最多边数个x),然后对于每个x,枚举边权等于x的边,将两个端点合并,按一个点来考虑。缩点后的图假设有siz个点,那么对于x,有个点集是合法的。对于每个x都这样求一遍,提前将边权相同的边放在同一个vector里,最后的复杂度就是O(m)。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cctype>
  7. #include<set>
  8. #include<vector>
  9. #include<queue>
  10. #include<map>
  11. using namespace std;
  12. typedef long long LL;
  13. inline LL read() {
  14. LL 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. #define pa pair<int,int>
  18. #define mp(a,b) make_pair(a,b)
  19. const int N = 500100;
  20. const int mod = 1e9 + 7;
  21. vector< pa > e[N];
  22. map<LL, int> mp;
  23. int fa[N], mi[N];
  24. LL c[N];
  25. int find(int x) {
  26. return x == fa[x] ? x : fa[x] = find(fa[x]);
  27. }
  28. int main() {
  29. int n = read(), m = read(), k = read(), Index = 0;
  30. mi[0] = 1;
  31. for (int i=1; i<=n; ++i) mi[i] = 1ll * mi[i - 1] * 2 % mod;
  32. LL sum = (1ll << k);
  33. for (int i=1; i<=n; ++i) c[i] = read();
  34. for (int i=1; i<=m; ++i) {
  35. int u = read(), v = read();
  36. LL x = c[u] ^ c[v];
  37. if (!mp[x]) mp[x] = ++Index;
  38. e[mp[x]].push_back(mp(u, v));
  39. }
  40. LL ans = 0;
  41. for (int i=1; i<=n; ++i) fa[i] = i;
  42. for (int i=1; i<=Index; ++i) {
  43. int siz = n;
  44. for (pa j : e[i]) {
  45. int u = j.first, v = j.second;
  46. if (find(u) != find(v)) {
  47. fa[fa[u]] = fa[v];
  48. siz --;
  49. }
  50. }
  51. ans = (ans + mi[siz]) % mod;
  52. for (pa j : e[i]) {
  53. int u = j.first, v = j.second;
  54. fa[u] = u, fa[v] = v;
  55. }
  56. }
  57. ans = (ans + 1ll * (sum - Index) % mod * mi[n] % mod) % mod;
  58. // sum:病毒所有的取值,减去Index个取值,剩下的取值对应的点集是随便取的,即2^n
  59. cout << ans;
  60. return 0;
  61. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注