[关闭]
@2368860385 2020-11-07T03:01:41.000000Z 字数 3434 阅读 193

后:day2

衢州

http://zhengruioi.com/blogof/gaolinxiang/blog/208
2018.8.5


预计:50+20+40
实际:50+20+0

T1

开场太困了,简直无法思考。
先做T2,直到最后来再看的时候,发现怎么做了。
想的是用线段树,很麻烦,其实用前缀和就好了。

T2

先写了暴力,然后发现还有个部分分 是 只有一条边大于等于1,感觉可做,于是写了两个小时多,20分,然后还没过。推错式子了。

T3

NTT模版忘了,于是暴力,忘记取模。

总结

1、由于T1开始没想出来,T2写了两个多小时,无果,心态有点炸。
2、考试策略不对,一个小时时应该先暂时放弃T2
3、做题顺序。


T1

先统一处理朝向一边的,然后处理朝向另一边的时候,看它与刚才统计的有多少相交的,减去即可。

  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 N = 100000;
  18. struct Node{
  19. int x,y,c,d;
  20. }A[N + 100];
  21. int sum1[N + N + 100], sum2[N + N + 100];
  22. bool vis[N + N + 100];
  23. int n;
  24. bool cmp1(Node A,Node B) {
  25. return A.c < B.c;
  26. }
  27. int getlen1(int x) {
  28. if (x <= 0) x = -x;
  29. return n - x;
  30. }
  31. int getlen2(int x) {
  32. if (x > n + 1) x = n + 1 - (x - (n + 1)); //注意!!!
  33. int len = x - 1;
  34. x -= 2;
  35. if (x & 1) return len - (sum1[x + N] - sum1[-x - 1 + N]);
  36. else return len - (sum2[x + N] - sum2[-x - 1 + N]);
  37. }
  38. int main() {
  39. n = read();int m = read();
  40. for (int i=1; i<=m; ++i) {
  41. A[i].x = read(), A[i].y = read();
  42. A[i].c = A[i].y - A[i].x; A[i].d = A[i].x + A[i].y;
  43. }
  44. sort(A + 1, A + m + 1, cmp1);
  45. int now = 1 - n;
  46. LL Ans = 0;
  47. for (int i=1; i<=m; ++i) {
  48. if (A[i].c < now) continue;
  49. while (now < A[i].c) {
  50. if (now & 1) sum1[now + N] = sum1[now - 2 + N];
  51. else sum2[now + N] = sum2[now - 2 + N];
  52. now ++;
  53. }
  54. if (now & 1) sum1[now + N] = 1 + sum1[now - 2 + N];
  55. else sum2[now + N] = 1 + sum2[now - 2 + N];
  56. Ans += getlen1(now);
  57. now ++;
  58. }
  59. while (now <= n - 1) {
  60. if (now & 1) sum1[now + N] = sum1[now - 2 + N];
  61. else sum2[now + N] = sum2[now - 2 + N];
  62. now ++;
  63. }
  64. for (int i=1-n; i<n; ++i) // 这里不要忘了
  65. if (i & 1) sum2[i + N] = sum2[i - 1 + N];
  66. else sum1[i + N] = sum1[i - 1 + N];
  67. for (int i=1; i<=m; ++i) {
  68. if (vis[A[i].d]) continue;
  69. vis[A[i].d] = true;
  70. Ans += getlen2(A[i].d);
  71. }
  72. cout << 1ll * n * n - Ans;
  73. return 0;
  74. }

T2

利用期望的线性性,可以分别计算每一条边的概率。
其实答案最后就是求方案数 * 贡献,所以可以枚举每一条边的贡献计算。
每种配对方案,一定是将左边的 男 / 女同学优先和右边的 女 / 男同学配对。我们设这条边断开后两个联通块的大小为 ,则经过它的贡献为:


前面是贡献,中间的组合数为选了那几个人,后面是站的位置。
然后发现

这一块只和ijm有关,可以预处理。

后面的化简后就之和i+j有关。

所以预处理f[k]为k=i+j的(1)式贡献(所有i+j=k的(1)式的和),然后对于每一条边(2)式就是可以O(m)计算了。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cctype>
  6. using namespace std;
  7. typedef long long LL;
  8. inline int read() {
  9. int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch=getchar()) if (ch=='-') f = -1;
  10. for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; return x * f;
  11. }
  12. const int N = 3010;
  13. const int mod = 1e9 + 7;
  14. int head[N], nxt[N << 1], to[N << 1], len[N << 1], siz[N], Enum;
  15. LL C[N][N], f[N << 1], P[N][N + N];
  16. LL Answer;
  17. int n, m;
  18. void add_edge(int u,int v,int w) {
  19. ++Enum; to[Enum] = v; len[Enum] = w; nxt[Enum] = head[u]; head[u] = Enum;
  20. ++Enum; to[Enum] = u; len[Enum] = w; nxt[Enum] = head[v]; head[v] = Enum;
  21. }
  22. void dfs(int u,int fa) {
  23. siz[u] = 1;
  24. for (int i=head[u]; i; i=nxt[i]) {
  25. int v = to[i];
  26. if (v == fa) continue;
  27. dfs(v, u);
  28. siz[u] += siz[v];
  29. for (int j=0; j<=m+m; ++j) {
  30. LL t = 1ll * len[i] * f[j] % mod;
  31. Answer = (Answer + t * P[siz[v]][j] % mod * P[n-siz[v]][m+m-j] % mod) % mod;
  32. }
  33. }
  34. }
  35. void init() {
  36. for (int i=1; i<=n; ++i) {
  37. P[i][0] = 1;
  38. for (int j=1; j<=m+m; ++j) {
  39. P[i][j] = 1ll * P[i][j - 1] * i % mod;
  40. }
  41. }
  42. C[0][0] = 1;
  43. for (int i=1; i<=m; ++i) {
  44. C[i][0] = 1;
  45. for (int j=1; j<=i; ++j) {
  46. C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
  47. }
  48. }
  49. for (int i=0; i<=m; ++i) {
  50. for (int j=0; j<=m; ++j) {
  51. LL t = min(i, m - j) + min(m - i, j);
  52. f[i + j] = (f[i + j] + 1ll * t * C[m][j] % mod * C[m][i] % mod) % mod;
  53. }
  54. }
  55. }
  56. int main() {
  57. n = read(), m = read();
  58. for (int i=1; i<n; ++i) {
  59. int u = read(), v = read(), w = read();
  60. add_edge(u, v, w);
  61. }
  62. init();
  63. dfs(1, 0);
  64. cout << Answer;
  65. return 0;
  66. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注