[关闭]
@2368860385 2018-08-31T08:30:13.000000Z 字数 4207 阅读 182

五校联考day1——2018.8.26

比赛总结


预计:100 + 100 + 10
实际:100 + 50 + 10

考试总结:

开始先看了一共半小时。想出了T1,T2,T3用容斥推出了小样例,所以一直感觉T3就是容斥。
T1:模拟题。写的时候 封装几个函数,可以好写些。

T2:开始感觉是陌上花开,于是想CDQ分治,(CDQ好像忘了怎么写了。。)想着想着发现是二维偏序,然后用树状数组直接求就好了。直接求前面有多少个数比它小,后面多少个数比他大。
感觉会爆int,改成了longlong。
怕中间会爆int,中间的乘法加上1ll。
之后造了一组数据检验,n=200000,a[]=1,2,3...
然后找一下规律,推一下结论,就用一个O(n)的程序跑出答案,在用写的程序跑,发现答案一样。于是就写T3了。
最后要取模,模1e9+7。。。于是没了50分。

T3:写完T2,然后来看T3,继续用容斥推。
先求出上面的环合法的方案数,为x,然后x*x就是总的。然后减去上下可能有相同的方案数。减去有一个相同的,加上两个相同,减去三个相同。那么现在又k个相同的,然后剩下的n-k个的颜色要求满足下面的环合法的方案数,然后这里求不出了。
n=4的情况就不能直接算出了,然后想了很长时间如何求,发现不能直接求。最后写了n=3的情况,n=4的讨论的太多,来不及写了。还有m=2的情况。


题解
T1:模拟
T2:树状数组,查前面有多少个数比它小,后面多少个数比他大。
T3:

将上面的环拆开,下面的拆开,再增加一个点n+1,现在就是给这个图染色,要求相邻三个点颜色不同,n+1和1相同。
枚举到每一行,右上的点的颜色一定不会和相邻的相同,它的状态只会和

左上角是第一行第一列,左下是第二行第一列,右上是第一行第i列,右下是第二行第i列
f[i][0/1/2][0/1/2] 表示当前填到第 i 列,右上角的点颜色和左上角左下
角都不同/和左上角相同/左下角相同,右下角的点颜色和左上角左下角
都不同/和左上角相同/左下角相同的方案数。

O(N)递推

  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 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 = 1000100;
  18. const LL mod = 1e9 + 7;
  19. LL f[N][3][3];
  20. int main() {
  21. LL n,m; cin >> n >> m;
  22. if (m == 2) {
  23. if (n & 1) cout << 0;
  24. else cout << 2;
  25. return 0;
  26. }
  27. LL m23 = 1ll * (m - 2) * (m - 3) % mod;
  28. LL m33 = 1ll * (m - 3) * (m - 3) % mod;
  29. LL m43 = 1ll * ((m - 4) * (m - 4) + (m - 3)) % mod;
  30. LL m2 = 1ll * (m - 2) % mod;
  31. LL m3 = 1ll * (m - 3) % mod;
  32. f[1][1][2] = 1ll * m * (m - 1) % mod;
  33. for (int i=2; i<=n+1; ++i) {
  34. f[i][0][0] = (
  35. (f[i-1][1][2] + f[i-1][2][1]) * m23 % mod +
  36. (f[i-1][1][0] + f[i-1][0][1] + f[i-1][2][0] + f[i-1][0][2]) * m33 % mod +
  37. (f[i-1][0][0]) * m43 % mod
  38. ) % mod;
  39. f[i][0][1] = (
  40. (f[i-1][0][0] + f[i-1][0][2]) * m3 % mod +
  41. (f[i-1][1][0] + f[i-1][1][2] + f[i-1][2][0]) * m2 % mod
  42. ) % mod;
  43. f[i][1][0] = (
  44. (f[i-1][0][0] + f[i-1][2][0]) * m3 % mod +
  45. (f[i-1][0][1] + f[i-1][2][1] + f[i-1][0][2]) * m2 % mod
  46. ) % mod;
  47. f[i][0][2] = (
  48. (f[i-1][0][0] + f[i-1][0][1]) * m3 % mod +
  49. (f[i-1][2][0] + f[i-1][2][1] + f[i-1][1][0]) * m2 % mod
  50. ) % mod;
  51. f[i][2][0] = (
  52. (f[i-1][0][0] + f[i-1][1][0]) * m3 % mod +
  53. (f[i-1][0][2] + f[i-1][1][2] + f[i-1][0][1]) * m2 % mod
  54. ) % mod;
  55. f[i][1][2] = (
  56. f[i-1][0][0] + f[i-1][0][1] + f[i-1][2][0] + f[i-1][2][1]
  57. ) % mod;
  58. f[i][2][1] = (
  59. f[i-1][0][0] + f[i-1][0][2] + f[i-1][1][0] + f[i-1][1][2]
  60. ) % mod;
  61. }
  62. LL ans = (f[n+1][1][2]) % mod;
  63. cout << ans;
  64. return 0;
  65. }

然后加上矩阵快速幂优化。
根据上面的转移方程推出矩阵。


因为 所以:
同理可知


因为A矩阵的大小是的,然后快速幂只进行次矩阵乘法,所以复杂度是

  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. const LL mod = 1e9 + 7;
  9. const int N = 7;
  10. struct Matrix{
  11. LL a[N][N];
  12. void init() {
  13. for (int i=0; i<N; ++i) a[i][i] = 1;
  14. }
  15. void Clear() {
  16. memset(a, 0, sizeof(a));
  17. }
  18. };
  19. Matrix mul(Matrix A, Matrix B) {
  20. Matrix C;
  21. C.Clear();
  22. for (int k=0; k<N; ++k)
  23. for (int i=0; i<N; ++i)
  24. for (int j=0; j<N; ++j)
  25. C.a[i][j] = (C.a[i][j] + 1ll * A.a[i][k] * B.a[k][j]) % mod;
  26. return C;
  27. }
  28. Matrix ksm(Matrix a,LL b) {
  29. Matrix ans;
  30. ans.Clear();
  31. ans.init();
  32. while (b) {
  33. if (b & 1) ans = mul(ans, a);
  34. a = mul(a, a);
  35. b >>= 1;
  36. }
  37. return ans;
  38. }
  39. int main() {
  40. LL n,m; cin >> n >> m;
  41. if (m == 2) {
  42. if (n & 1) cout << 0;
  43. else cout << 2;
  44. return 0;
  45. }
  46. LL m23 = 1ll * (m - 2) * (m - 3) % mod;
  47. LL m33 = 1ll * (m - 3) * (m - 3) % mod;
  48. LL m43 = 1ll * ((m - 4) * (m - 4) + (m - 3)) % mod;
  49. LL m2 = 1ll * (m - 2) % mod;
  50. LL m3 = 1ll * (m - 3) % mod;
  51. Matrix A; A.Clear(); //--清空A!!!
  52. if (m >= 4) A.a[0][0] = m43;
  53. A.a[0][1] = A.a[0][2] = A.a[0][3] = A.a[0][5] = m33;
  54. A.a[0][4] = A.a[0][6] = m23;
  55. A.a[1][0] = A.a[1][2] = A.a[2][0] = A.a[2][1] = A.a[3][0] = A.a[3][5] = A.a[5][0] = A.a[5][3] = m3;
  56. A.a[1][3] = A.a[1][4] = A.a[1][5] = A.a[2][3] = A.a[2][5] = A.a[2][6] =
  57. A.a[3][1] = A.a[3][2] = A.a[3][6] = A.a[5][1] = A.a[5][2] = A.a[5][4] = m2;
  58. A.a[4][0] = A.a[4][1] = A.a[4][5] = A.a[4][6] = A.a[6][0] = A.a[6][2] = A.a[6][3] = A.a[6][4] = 1;
  59. A = ksm(A, n);
  60. LL ans = A.a[4][4] * m % mod * (m - 1) % mod;
  61. cout << ans;
  62. return 0;
  63. }

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