[关闭]
@Chilling 2018-04-27T11:35:05.000000Z 字数 19499 阅读 707

ACM


计算几何

注意

两圆相交面积
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define PI acos(-1.0)
  4. double dis(double x1, double y1, double x2, double y2)
  5. {
  6. return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  7. }
  8. double cos_angle(double a, double b, double c)
  9. {
  10. return 0.5 * (a * a + c * c - b * b) / (a * c);
  11. }
  12. double get_area(double x1, double y1, double r1, double x2, double y2, double r2)
  13. {
  14. double d, s, s1_, s2_, s1_tri, s2_tri, an1, an2;
  15. d = dis(x1, y1, x2, y2);
  16. if (d >= r1 + r2 || !r1 || !r2) //相切、相离、考虑等于0
  17. return 0;
  18. if (d + r1 <= r2) //包含
  19. return PI * r1 * r1;
  20. if (d + r2 <= r1) //包含
  21. return PI * r2 * r2;
  22. an1 = acos(cos_angle(r1, r2, d));
  23. an2 = acos(cos_angle(r2, r1, d));
  24. s1_tri = 0.5 * r1 * r1 * sin(an1 * 2);
  25. s2_tri = 0.5 * r2 * r2 * sin(an2 * 2);
  26. s1_ = r1 * r1 * an1;
  27. s2_ = r2 * r2 * an2;
  28. s = (s1_ - s1_tri) + (s2_ - s2_tri);
  29. return s;
  30. }

三角形中整点个数
  1. int area()
  2. {
  3. return abs((a * d + c * f + b * e - a * f - b * c - d * e) / 2);
  4. }
  5. int gcd(int x, int y)
  6. {
  7. if (y == 0)return x;
  8. else
  9. return gcd(y, x % y);
  10. }
  11. int main ()
  12. {
  13. int t;
  14. scanf("%d", &t);
  15. while (t--)
  16. {
  17. scanf("%d%d%d%d%d%d", &a, &b, &c, &d, &e, &f);
  18. int s = area();
  19. int l1 = gcd(abs(a - c), abs(b - d));
  20. int l2 = gcd(abs(a - e), abs(b - f));
  21. int l3 = gcd(abs(c - e), abs(d - f));
  22. printf("%d\n", s - (l1 + l2 + l3) / 2 + 1);
  23. }
  24. return 0;
  25. }

三角形面积


M*N方格中矩形正方形数量

矩形:
正方形:

锥形

给出锥形的表面积(包括底部)S,当的时候,体积最大。


优先队列

  1. struct cmp1
  2. {
  3. bool operator ()(int x, int y)
  4. {
  5. return x > y;//小的优先级高
  6. }
  7. };
  8. struct node
  9. {
  10. int x, y;
  11. friend bool operator < (node a, node b)
  12. {
  13. return a.x > b.x;//结构体中,x小的优先级高
  14. }
  15. };
  16. priority_queue<int, vector<int>, cmp1>q2;
  17. priority_queue<node>q4;

多重背包的二进制优化

  1. //几种不同类型有固定数量的物品拆分成01背包
  2. //这个姿势貌似更好
  3. for (i = 1; i <= m; i++)
  4. {
  5. scanf("%d%d%d", &p, &h, &c); //价值,重量,个数
  6. for (j = 1; j <= c; j *= 2)
  7. {
  8. v[cnt] = j * p; //分堆后每堆的价值
  9. w[cnt++] = j * h; //每堆的重量
  10. c -= j;
  11. }
  12. if (c > 0)
  13. {
  14. v[cnt] = c * p;
  15. w[cnt++] = c * h;
  16. }
  17. }


数学

第一类Stirling数

第一类斯特林数是有正负的,其绝对值是包含n个元素的集合分作k个环排列的方法数目。
递推公式为:   
边界条件:
一些性质:  

第二类Stirling数

第二类斯特林数是把包含n个元素的集合划分为正好k个非空子集的方法的数目。   
递推公式为:   ,   

考虑第p个物品,p可以单独构成一个非空集合,此时前p-1个物品构成k-1个非空的
不可辨别的集合,方法数为S(p-1,k-1);
也可以前p-1种物品构成k个非空的不可辨别的集合,
第p个物品放入任意一个中,这样有k*S(p-1,k)种方法。

sdut 2883

n场比赛,m张牌(n>=m)每场比赛用一张牌,
每张牌至少用一次,问有几种方案数。
分析:n场比赛划分成m个集合,每个集合里的比赛只用同一张牌,
没有空的集合。也就是说把包含n个元素的集合划分为正好m个非空子集的方法的数目,
再乘m的全排列。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const ll mod = 1e9 + 7;
  5. ll sum[110][110];
  6. ll jiec[102];
  7. int main()
  8. {
  9. jiec[0] = 1;
  10. jiec[1] = 1;
  11. jiec[2] = 2;
  12. for (ll i = 3; i < 102; i++)
  13. jiec[i] = (jiec[i - 1] * i) % mod;
  14. for (ll i = 0; i <= 102; i++)
  15. {
  16. for (ll j = 0; j <= 102; j++)
  17. {
  18. if ( j == 0 || j > i )sum[i][j] = 0;
  19. else if ( i == j || j == 1 )sum[i][j] = 1;
  20. else sum[i][j] = ( sum[i - 1][j - 1] + j * sum[i - 1][j] ) % mod;
  21. }
  22. }
  23. int n, m;
  24. while ( scanf("%d %d", &n, &m) != EOF )
  25. {
  26. printf("%lld\n", (jiec[m]*sum[n][m] ) % mod );
  27. }
  28. return 0;
  29. }
sdut 3144

现在给你一个数集S的大小n,请输出将它划分为集合的方法总数ans是多少?

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const ll mod = 1e9 + 7;
  5. const int maxn = 5002;
  6. ll sum[2][maxn];
  7. ll ans[maxn];
  8. void cal()
  9. {
  10. for (ll i = 0; i < maxn; i++)
  11. {
  12. ans[i] = 0;
  13. for (ll j = 0; j < maxn; j++)
  14. {
  15. if ( j == 0 || j > i )sum[i % 2][j] = 0;
  16. else if ( i == j || j == 1 )sum[i % 2][j] = 1;
  17. else sum[i % 2][j] = ( sum[ (i - 1) % 2 ][j - 1] + j * sum[ (i - 1) % 2 ][j] ) % mod;
  18. ans[i] = (ans[i] + sum[i % 2][j]) % mod;
  19. }
  20. }
  21. }
  22. int main()
  23. {
  24. cal();
  25. int n, cas = 1;
  26. while ( scanf("%d", &n) != EOF )
  27. {
  28. printf("Case #%d: %lld\n", cas++, ans[n] % mod );
  29. }
  30. return 0;
  31. }
快速幂取余
  1. LL quick(LL x,LL m,LL n)//x^m%mod
  2. {
  3. LL ans=1;
  4. while(m>0)
  5. {
  6. if(m%2==1)
  7. ans=ans*x%mod;
  8. x=x*x%mod;
  9. m=m/2;
  10. }
  11. return ans;
  12. }

矩阵
  1. struct Matrix
  2. {
  3. int m[10][10];
  4. }M;
  5. Matrix Mult(Matrix a,Matrix b) //矩阵乘法
  6. {
  7. Matrix ans;
  8. for(int i=0;i<n;i++)
  9. {
  10. for(int j=0;j<n;j++)
  11. {
  12. ans.m[i][j]=0;
  13. for(int k=0;k<n;k++)
  14. {
  15. ans.m[i][j]+=a.m[i][k]*b.m[k][j];
  16. ans.m[i][j]%=mod;
  17. }
  18. }
  19. }
  20. return ans;
  21. }
  22. Matrix quickpow(Matrix a,int b) //矩阵a的b次方-快速幂
  23. {
  24. Matrix ans;
  25. for(int i=0;i<n;i++)
  26. {
  27. for(int j=0;j<n;j++)
  28. {
  29. if(i==j)
  30. ans.m[i][j]=1;
  31. else
  32. ans.m[i][j]=0;
  33. }
  34. }
  35. while(b)
  36. {
  37. if(b&1)
  38. ans=Mult(ans,a);
  39. a=Mult(a,a);
  40. b/=2;
  41. }
  42. return ans;
  43. }
Euler_phi函数
  1. int phi(int n)
  2. {
  3. int m = (int)sqrt(n + 0.5);
  4. int ans = n;
  5. for (int i = 2; i <= m; i++)
  6. if (n % i == 0)
  7. {
  8. ans = ans / i * (i - 1);
  9. while (n % i == 0)
  10. n /= i;
  11. }
  12. if (n > 1)
  13. ans = ans / n * (n - 1);
  14. return ans;
  15. }
:埃式筛法
  1. bool isprime[N];
  2. void primeform(int maxn) //0到maxn内的素数
  3. {
  4. memset(isprime, true, sizeof(isprime));
  5. int m = (int)sqrt(maxn + 0.5) + 1;
  6. for (int i = 2; i < m; i++)
  7. {
  8. if (isprime[i])
  9. for (int j = i * 2; j <= maxn; j += i)
  10. isprime[j] = false;
  11. }
  12. }
:快速线性筛法
  1. bool isprime[maxn]; //是否素数
  2. int prime[maxn]; //素数表
  3. void primeform(int maxn) //0-maxn素数
  4. {
  5. int cnt = 0;
  6. memset(isprime, true, sizeof(isprime));
  7. for (int i = 2; i <= maxn; i++)
  8. {
  9. if (isprime[i])
  10. prime[cnt++] = i; //打表
  11. for (int j = 0; (j < cnt && i * prime[j] <= maxn); j++)
  12. {
  13. isprime[i * prime[j]] = false;
  14. if (i % prime[j] == 0)
  15. break;
  16. }
  17. }
  18. }
高效求n以内素数个数
  1. #include<bits/stdc++.h>
  2. #define LL long long
  3. using namespace std;
  4. LL f[340000], g[340000], n;
  5. void init()
  6. {
  7. LL i, j, m;
  8. for (m = 1; m * m <= n; ++m)
  9. f[m] = n / m - 1;
  10. for (i = 1; i <= m; ++i)
  11. g[i] = i - 1;
  12. for (i = 2; i <= m; ++i)
  13. {
  14. if (g[i] == g[i - 1])
  15. continue;
  16. for (j = 1; j <= min(m - 1, n / i / i); ++j)
  17. {
  18. if (i * j < m)
  19. f[j] -= f[i * j] - g[i - 1];
  20. else
  21. f[j] -= g[n / i / j] - g[i - 1];
  22. }
  23. for (j = m; j >= i * i; --j)
  24. g[j] -= g[j / i] - g[i - 1];
  25. }
  26. }
  27. int main()
  28. {
  29. while (scanf("%lld", &n) != EOF)
  30. {
  31. init();
  32. printf("%lld\n", f[1]);
  33. }
  34. return 0;
  35. }
阶乘最后非0位
  1. //求阶乘最后非零位,复杂度O(nlogn)
  2. //返回该位,n以字符串方式传入
  3. #define MAXN 10000
  4. int lastdigit(char* buf)
  5. {
  6. const int mod[20] = {1, 1, 2, 6, 4, 2, 2, 4, 2, 8, 4, 4, 8, 4, 6, 8, 8, 6, 8, 2};
  7. int len = strlen(buf), a[MAXN], i, c, ret = 1;
  8. if (len == 1)
  9. return mod[buf[0] - '0'];
  10. for (i = 0; i < len; i++)
  11. a[i] = buf[len - 1 - i] - '0';
  12. for (; len; len -= !a[len - 1])
  13. {
  14. ret = ret * mod[a[1] % 2 * 10 + a[0]] % 5;
  15. for (c = 0, i = len - 1; i >= 0; i--)
  16. c = c * 10 + a[i], a[i] = c / 5, c %= 5;
  17. }
  18. return ret + ret % 2 * 5;
  19. }
素数个数的位数
  1. int ans = double(n - log10(n) - log10(log(10)));
  2. printf("%d\n", ans + 1);

拓展欧几里得

mod 的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元。
通过求b关于p的乘法逆元k,将a乘上k再模p,即 mod 。其结果与 mod 等价

  1. //ax+by=gcd(a,b),所求的x即为a mod b的逆元(a^(-1)),y为b mod a的逆元
  2. void ex_gcd(LL a,LL b)
  3. {
  4. if(b==0)
  5. {
  6. x=1;
  7. y=0;
  8. return ;
  9. }
  10. ex_gcd(b,a%b);
  11. int t=x;
  12. x=y;
  13. y=t-a/b*y;
  14. }

A,B互质,组合为其他数

不能表示的数的个数:(A-1)*(B-1)/2
最大不能表示的数:A*B-A-B

组合数奇偶性的判断

对于C(n,k),若n&k == k ,则c(n,k)为奇数,否则为偶数

青蛙跳台阶问题
卡特兰数


另类递推式:

递推关系的解为:

递推关系的另类解为:

  1. a[0]=1,a[1]=1;
  2. for(i=2;i<=n;i++)
  3. a[i]=a[i-1]*(4*i-2)/(i+1);
  1. a[0]=1,a[1]=1;
  2. for(i=2;i<=n;i++)
  3. for(j=0;j<i;j++)
  4. a[i]=a[i]+a[j]*a[i-j-1];
汉诺塔

递推式:


树状数组

  1. int lowbit(int x)
  2. {
  3. return x & (-x);
  4. }
  5. void change(int x, int y) //在x点加上值y
  6. {
  7. for (int i = x; i <= n; i += lowbit(i))
  8. a[i] += y;
  9. }
  10. int sum(int x) //1到x的和
  11. {
  12. int sum = 0;
  13. for (int i = x; i > 0; i -= lowbit(i))
  14. sum += a[i];
  15. return sum;
  16. }

高精度

N!
  1. #include<stdio.h>
  2. #include<string.h>
  3. #define N 3000
  4. int f[N];
  5. int main()
  6. {
  7. int i, j, n;
  8. scanf("%d", &n);
  9. memset(f, 0, sizeof(f));
  10. f[0] = 1;
  11. for (i = 2; i <= n; i++)
  12. {
  13. int c = 0;
  14. for (j = 0; j < N; j++)
  15. {
  16. int s = f[j] * i + c;
  17. f[j] = s % 10;
  18. c = s / 10;
  19. }
  20. }
  21. for (j = N - 1; j >= 0; j--)
  22. {
  23. if (f[j])
  24. break;
  25. }
  26. for (i = j; i >= 0; i--)
  27. {
  28. printf("%d", f[i]);
  29. }
  30. printf("\n");
  31. return 0;
  32. }
A/B
  1. #include<stdio.h>
  2. #include<string.h>
  3. char sa[1111], sb[1111];
  4. int s[1111], la, lb, i, flag, k, j;
  5. void jianfa()
  6. {
  7. for (i = lb - 1; i > 0; i--)
  8. {
  9. if (sa[i] < sb[i])
  10. {
  11. sa[i] += 10;
  12. sa[i - 1]--;
  13. }
  14. }
  15. for (i = lb - 1; i >= 0; i--)
  16. sa[i] = sa[i] - sb[i] + '0';
  17. }
  18. int main()
  19. {
  20. while (scanf("%s%s", sa, sb) != EOF)
  21. {
  22. memset(s, 0, sizeof(s));
  23. k = 0;
  24. flag = 1;
  25. la = strlen(sa);
  26. lb = strlen(sb);
  27. if (la < lb || (la == lb && strcmp(sa, sb) < 0))
  28. printf("0\n");
  29. else
  30. {
  31. while (flag)
  32. {
  33. while (strcmp(sa, sb) >= 0)
  34. {
  35. jianfa();
  36. s[k]++;
  37. }
  38. k++;
  39. if (la == lb)
  40. flag = 0;
  41. for (i = lb; i >= 1; i--)
  42. sb[i] = sb[i - 1];
  43. sb[0] = '0';
  44. lb++;
  45. sb[lb] = '\0';
  46. }
  47. }
  48. for (i = 0; i < k; i++)
  49. if (s[i] != 0)
  50. break;
  51. for (j = i; j < k; j++)
  52. printf("%d", s[j]);
  53. printf("\n");
  54. }
  55. return 0;
  56. }
A+B
  1. #include<stdio.h>
  2. #include<string.h>
  3. int a[555], b[555], s[555], la, lb, i, l;
  4. void jiafa()
  5. {
  6. memset(s, 0, sizeof(s));
  7. for (i = 0; i < l; i++)
  8. s[i] = a[i] + b[i];
  9. for (i = 0; i <= l; i++)
  10. {
  11. s[i + 1] += s[i] / 10;
  12. s[i] %= 10;
  13. }
  14. for (i = l; i > 0; i--)
  15. if (s[i] == 0)
  16. l--;
  17. else break;
  18. for (i = l; i >= 0; i--)
  19. printf("%d", s[i]);
  20. printf("\n");
  21. }
  22. int main()
  23. {
  24. char sa[555], sb[555];
  25. while (scanf("%s%s", sa, sb) != EOF)
  26. {
  27. memset(a, 0, sizeof(a));
  28. memset(b, 0, sizeof(b));
  29. la = strlen(sa);
  30. lb = strlen(sb);
  31. for (i = 0; i < la; i++)
  32. a[la - i - 1] = sa[i] - '0';
  33. for (i = 0; i < lb; i++)
  34. b[lb - i - 1] = sb[i] - '0';
  35. l = la > lb ? la : lb;
  36. jiafa();
  37. }
  38. return 0;
  39. }
A-B
  1. #include<stdio.h>
  2. #include<string.h>
  3. void jianfa(int *a, int *b, int l)
  4. {
  5. int i, j, s[111], flag = 0;
  6. memset(s, 0, sizeof(s));
  7. for (i = 0; i < l - 1; i++)
  8. {
  9. if (a[i] < b[i])
  10. {
  11. a[i] += 10;
  12. a[i + 1]--;
  13. }
  14. s[i] = a[i] - b[i];
  15. }
  16. s[l - 1] = a[l - 1] - b[l - 1];
  17. for (i = l - 1; i >= 0; i--)
  18. {
  19. if (s[i] != 0)
  20. {
  21. flag = 1;
  22. break;
  23. }
  24. }
  25. if (flag == 0)
  26. printf("0\n");
  27. else
  28. for (j = i; j >= 0; j--)
  29. printf("%d", s[j]);
  30. printf("\n");
  31. }
  32. int f(int *a, int *b, int la, int lb)
  33. {
  34. int i;
  35. for (i = la - 1; i >= 0; i--)
  36. {
  37. if (a[i] > b[i])
  38. {
  39. return 1;
  40. break;
  41. }
  42. if (a[i] < b[i])
  43. {
  44. return 0;
  45. break;
  46. }
  47. }
  48. return -1;
  49. }
  50. int main()
  51. {
  52. char sa[111], sb[111];
  53. int a[111], b[111], ta, tb, i, j, flag, la, lb;
  54. while (scanf("%s%s", sa, sb) != EOF)
  55. {
  56. ta = 0, tb = 0;
  57. memset(a, 0, sizeof(a));
  58. memset(b, 0, sizeof(b));
  59. la = strlen(sa);
  60. lb = strlen(sb);
  61. for (i = 0, j = la - 1; j >= 0; i++, j--)
  62. a[i] = sa[j] - '0';
  63. for (i = 0, j = lb - 1; j >= 0; i++, j--)
  64. b[i] = sb[j] - '0';
  65. for (i = la - 1; i >= 0; i--)
  66. {
  67. if (a[i] != 0)
  68. {
  69. ta = 1;
  70. la = i + 1;
  71. break;
  72. }
  73. }
  74. for (i = lb - 1; i >= 0; i--)
  75. {
  76. if (b[i] != 0)
  77. {
  78. tb = 1;
  79. lb = i + 1;
  80. break;
  81. }
  82. }
  83. if (ta + tb == 0)
  84. printf("0\n");
  85. else
  86. {
  87. if (la < lb)
  88. {
  89. printf("-");
  90. jianfa(b, a, lb);
  91. }
  92. else if (la > lb)
  93. jianfa(a, b, la);
  94. else
  95. {
  96. if (f(a, b, la, lb) == 1)
  97. jianfa(a, b, la);
  98. else if (f(a, b, la, lb) == 0)
  99. {
  100. printf("-");
  101. jianfa(b, a, lb);
  102. }
  103. else
  104. printf("0\n");
  105. }
  106. }
  107. }
  108. return 0;
  109. }
A*B
  1. #include<stdio.h>
  2. #include<string.h>
  3. int main()
  4. {
  5. char sa[44], sb[44];
  6. int a[44], b[44], la, lb, i, j, sum[88], k, x;
  7. while (scanf("%s%s", sa, sb) != EOF)
  8. {
  9. k = 0;
  10. memset(a, 0, sizeof(a));
  11. memset(b, 0, sizeof(b));
  12. memset(sum, 0, sizeof(sum));
  13. la = strlen(sa);
  14. lb = strlen(sb);
  15. for (i = 0, j = la - 1; j >= 0; j--, i++)
  16. a[i] = sa[j] - '0';
  17. for (i = 0, j = lb - 1; j >= 0; j--, i++)
  18. b[i] = sb[j] - '0';
  19. for (i = 0; i < la; i++)
  20. {
  21. for (j = 0, k = i; j < lb; j++)
  22. {
  23. sum[k] += a[i] * b[j];
  24. k++;
  25. }
  26. }
  27. for (i = 0; i < k - 1; i++)
  28. {
  29. sum[i + 1] += sum[i] / 10;
  30. sum[i] %= 10;
  31. }
  32. if (sum[k - 1] >= 10)
  33. {
  34. sum[k] = sum[k - 1] / 10;
  35. sum[k - 1] %= 10;
  36. x = k;
  37. }
  38. else
  39. x = k - 1;
  40. for (i = x; i >= 0; i--)
  41. printf("%d", sum[i]);
  42. printf("\n");
  43. }
  44. }

RMQ

一维
  1. #include<stdio.h>
  2. #include<algorithm>
  3. using namespace std;
  4. int a[50005], dpmin[50005][16], dpmax[50005][16];
  5. int main()
  6. {
  7. int i, n, q, st, en, j, d;
  8. while (scanf("%d%d", &n, &q) != EOF)
  9. {
  10. for (i = 1; i <= n; i++)
  11. scanf("%d", &a[i]);
  12. for (i = 1; i <= n; i++)
  13. {
  14. dpmin[i][0] = a[i];
  15. dpmax[i][0] = a[i];
  16. }
  17. for (i = 1; (1 << i) <= n; i++) //区间长度
  18. for (j = 1; j + (1 << i) - 1 <= n; j++) //起点
  19. {
  20. dpmax[j][i] = max(dpmax[j][i - 1], dpmax[j + (1 << i - 1)][i - 1]);
  21. dpmin[j][i] = min(dpmin[j][i - 1], dpmin[j + (1 << i - 1)][i - 1]);
  22. }
  23. while (q--)
  24. {
  25. scanf("%d%d", &st, &en);
  26. d = 0;
  27. while ((1 << d + 1) <= en - st + 1) d++;
  28. printf("%d\n", (max(dpmax[st][d], dpmax[en - (1 << d) + 1][d]) - min(dpmin[st][d], dpmin[en - (1 << d) + 1][d])));
  29. }
  30. }
  31. return 0;
  32. }

二维
  1. #include<stdio.h>
  2. #include<algorithm>
  3. using namespace std;
  4. int mp[255][255];
  5. int dpmin[255][255][8][8]; //若起点为(0,0),2^8=256
  6. int dpmax[255][255][8][8];
  7. //二维RMQ,dp[x][y][i][j]
  8. //表示从(x,y)点到右下角为(x+2^i-1,y+2^j-1)矩形内最小值
  9. void RMQ(int n, int m) //n*m的矩阵
  10. {
  11. for (int i = 0; (1 << i) <= n; i++)
  12. {
  13. for (int j = 0; (1 << j) <= m; j++)
  14. {
  15. if (!i && !j) continue;
  16. for (int r = 1; r + (1 << i) - 1 <= n; r++)
  17. for (int c = 1; c + (1 << j) - 1 <= m; c++)
  18. {
  19. if (!j)
  20. {
  21. dpmax[r][c][i][j] = max(dpmax[r][c][i - 1][j], dpmax[r + (1 << (i - 1))][c][i - 1][j]);
  22. dpmin[r][c][i][j] = min(dpmin[r][c][i - 1][j], dpmin[r + (1 << (i - 1))][c][i - 1][j]);
  23. }
  24. else
  25. {
  26. dpmax[r][c][i][j] = max(dpmax[r][c][i][j - 1], dpmax[r][c + (1 << (j - 1))][i][j - 1]);
  27. dpmin[r][c][i][j] = min(dpmin[r][c][i][j - 1], dpmin[r][c + (1 << (j - 1))][i][j - 1]);
  28. }
  29. }
  30. }
  31. }
  32. }
  33. int querymax(int lx, int ly, int rx, int ry)
  34. {
  35. int kx = 0, ky = 0;
  36. while (lx + (1 << (1 + kx)) - 1 <= rx) kx++;
  37. while (ly + (1 << (1 + ky)) - 1 <= ry) ky++;
  38. int m1 = dpmax[lx][ly][kx][ky];
  39. int m2 = dpmax[rx - (1 << kx) + 1][ly][kx][ky];
  40. int m3 = dpmax[lx][ry - (1 << ky) + 1][kx][ky];
  41. int m4 = dpmax[rx - (1 << kx) + 1][ry - (1 << ky) + 1][kx][ky];
  42. return max(max(m1, m2), max(m3, m4));
  43. }
  44. int querymin(int lx, int ly, int rx, int ry)
  45. {
  46. int kx = 0, ky = 0;
  47. while (lx + (1 << (1 + kx)) - 1 <= rx) kx++;
  48. while (ly + (1 << (1 + ky)) - 1 <= ry) ky++;
  49. int m1 = dpmin[lx][ly][kx][ky];
  50. int m2 = dpmin[rx - (1 << kx) + 1][ly][kx][ky];
  51. int m3 = dpmin[lx][ry - (1 << ky) + 1][kx][ky];
  52. int m4 = dpmin[rx - (1 << kx) + 1][ry - (1 << ky) + 1][kx][ky];
  53. return min(min(m1, m2), min(m3, m4));
  54. }
  55. int main()
  56. {
  57. int n, b, q;
  58. scanf("%d%d%d", &n, &b, &q);
  59. for (int i = 1; i <= n; i++)
  60. for (int j = 1; j <= n; j++)
  61. {
  62. scanf("%d", &mp[i][j]);
  63. dpmax[i][j][0][0] = mp[i][j];
  64. dpmin[i][j][0][0] = mp[i][j];
  65. }
  66. RMQ(n, n);
  67. while (q--)
  68. {
  69. int x, y;
  70. scanf("%d%d", &x, &y);
  71. printf("%d\n", querymax(x, y, x + b - 1, y + b - 1) - querymin(x, y, x + b - 1, y + b - 1));
  72. }
  73. return 0;
  74. }

线段树

普通
  1. #include <bits/stdc++.h>
  2. #define MAXN 100010
  3. #define inf 0x3f3f3f3f
  4. using namespace std;
  5. struct node
  6. {
  7. int l, r; //区间[l,r]
  8. int add;//区间的延时标记
  9. int sum;//区间和
  10. int mx; //区间最大值
  11. int mn; //区间最小值
  12. } tree[MAXN << 2]; //一定要开到4倍多的空间
  13. void pushup(int index)
  14. {
  15. tree[index].sum = tree[index << 1].sum + tree[index << 1 | 1].sum;
  16. tree[index].mx = max(tree[index << 1].mx, tree[index << 1 | 1].mx);
  17. tree[index].mn = min(tree[index << 1].mn, tree[index << 1 | 1].mn);
  18. }
  19. void pushdown(int index)
  20. {
  21. //说明该区间之前更新过
  22. //要想更新该区间下面的子区间,就要把上次更新该区间的值向下更新
  23. if (tree[index].add > 0)
  24. {
  25. //替换原来的值
  26. /*
  27. tree[index<<1].sum = (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add;
  28. tree[index<<1|1].sum = (tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add;
  29. tree[index<<1].mx = tree[index].add;
  30. tree[index<<1|1].mx = tree[index].add;
  31. tree[index<<1].mn = tree[index].add;
  32. tree[index<<1|1].mn = tree[index].add;
  33. tree[index<<1].add = tree[index].add;
  34. tree[index<<1|1].add = tree[index].add;
  35. tree[index].add = 0;*/
  36. //在原来的值的基础上加上val
  37. tree[index << 1].sum += (tree[index << 1].r - tree[index << 1].l + 1) * tree[index].add;
  38. tree[index << 1 | 1].sum += (tree[index << 1 | 1].r - tree[index << 1 | 1].l + 1) * tree[index].add;
  39. tree[index << 1].mx += tree[index].add;
  40. tree[index << 1 | 1].mx += tree[index].add;
  41. tree[index << 1].mn += tree[index].add;
  42. tree[index << 1 | 1].mn += tree[index].add;
  43. tree[index << 1].add += tree[index].add;
  44. tree[index << 1 | 1].add += tree[index].add;
  45. tree[index].add = 0;
  46. }
  47. }
  48. void build(int l, int r, int index)
  49. {
  50. tree[index].l = l;
  51. tree[index].r = r;
  52. tree[index].add = 0;//刚开始一定要清0
  53. if (l == r)
  54. {
  55. scanf("%d", &tree[index].sum);
  56. tree[index].mn = tree[index].mx = tree[index].sum;
  57. return ;
  58. }
  59. int mid = (l + r) >> 1;
  60. build(l, mid, index << 1);
  61. build(mid + 1, r, index << 1 | 1);
  62. pushup(index);
  63. }
  64. void updata(int l, int r, int index, int val)
  65. {
  66. if (l <= tree[index].l && r >= tree[index].r)
  67. {
  68. /*把原来的值替换成val,因为该区间有tree[index].r-tree[index].l+1
  69. 个数,所以区间和 以及 最值为:
  70. */
  71. /*tree[index].sum = (tree[index].r-tree[index].l+1)*val;
  72. tree[index].mn = val;
  73. tree[index].mx = val;
  74. tree[index].add = val;//延时标记*/
  75. //在原来的值的基础上加上val,因为该区间有tree[index].r-tree[index].l+1
  76. //个数,所以区间和 以及 最值为:
  77. tree[index].sum += (tree[index].r - tree[index].l + 1) * val;
  78. tree[index].mn += val;
  79. tree[index].mx += val;
  80. tree[index].add += val;//延时标记
  81. return ;
  82. }
  83. pushdown(index);
  84. int mid = (tree[index].l + tree[index].r) >> 1;
  85. if (l <= mid)
  86. {
  87. updata(l, r, index << 1, val);
  88. }
  89. if (r > mid)
  90. {
  91. updata(l, r, index << 1 | 1, val);
  92. }
  93. pushup(index);
  94. }
  95. int query(int l, int r, int index)
  96. {
  97. if (l <= tree[index].l && r >= tree[index].r)
  98. {
  99. //return tree[index].sum;
  100. return tree[index].mx;
  101. //return tree[index].mn;
  102. }
  103. pushdown(index);
  104. int mid = (tree[index].l + tree[index].r) >> 1;
  105. int ans = 0;
  106. int Max = 0;
  107. int Min = inf;
  108. if (l <= mid)
  109. {
  110. ans += query(l, r, index << 1);
  111. Max = max(query(l, r, index << 1), Max);
  112. Min = min(query(l, r, index << 1), Min);
  113. }
  114. if (r > mid)
  115. {
  116. ans += query(l, r, index << 1 | 1);
  117. Max = max(query(l, r, index << 1 | 1), Max);
  118. Min = min(query(l, r, index << 1 | 1), Min);
  119. }
  120. //return ans;
  121. return Max;
  122. //return Min;
  123. }
  124. int main()
  125. {
  126. int n, m, q, x, y, z;
  127. while (~scanf("%d%d", &n, &m))
  128. {
  129. build(1, n, 1);
  130. while (m--)
  131. {
  132. scanf("%d", &q);
  133. if (q == 1)
  134. {
  135. cout << "查询:(x,y)" << endl;
  136. scanf("%d %d", &x, &y);
  137. cout << query(x, y, 1) << endl;
  138. }
  139. else
  140. {
  141. cout << "更新(x,y)为z:" << endl;
  142. scanf("%d %d %d", &x, &y, &z);
  143. updata(x, y, 1, z);
  144. for (int i = 1; i <= n; ++i)
  145. {
  146. printf("a[%d] = %d\n", i, query(i, i, 1));
  147. }
  148. }
  149. }
  150. }
  151. return 0;
  152. }
二维
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int INF = 0x3f3f3f3f;
  4. const int MAXN = 1010;
  5. struct Nodey
  6. {
  7. int l, r;
  8. int Max, Min;
  9. };
  10. int locy[MAXN], locx[MAXN];
  11. struct Nodex
  12. {
  13. int l, r;
  14. Nodey sty[MAXN * 4];
  15. void build(int i, int _l, int _r)
  16. {
  17. sty[i].l = _l;
  18. sty[i].r = _r;
  19. sty[i].Max = -INF;
  20. sty[i].Min = INF;
  21. if (_l == _r)
  22. {
  23. locy[_l] = i;
  24. return;
  25. }
  26. int mid = (_l + _r) / 2;
  27. build(i << 1, _l, mid);
  28. build((i << 1) | 1, mid + 1, _r);
  29. }
  30. int queryMin(int i, int _l, int _r)
  31. {
  32. if (sty[i].l == _l && sty[i].r == _r)
  33. return sty[i].Min;
  34. int mid = (sty[i].l + sty[i].r) / 2;
  35. if (_r <= mid)return queryMin(i << 1, _l, _r);
  36. else if (_l > mid)return queryMin((i << 1) | 1, _l, _r);
  37. else return min(queryMin(i << 1, _l, mid), queryMin((i << 1) | 1, mid + 1, _r));
  38. }
  39. int queryMax(int i, int _l, int _r)
  40. {
  41. if (sty[i].l == _l && sty[i].r == _r)
  42. return sty[i].Max;
  43. int mid = (sty[i].l + sty[i].r) / 2;
  44. if (_r <= mid)return queryMax(i << 1, _l, _r);
  45. else if (_l > mid)return queryMax((i << 1) | 1, _l, _r);
  46. else return max(queryMax(i << 1, _l, mid), queryMax((i << 1) | 1, mid + 1, _r));
  47. }
  48. } stx[MAXN * 4];
  49. int n;
  50. void build(int i, int l, int r)
  51. {
  52. stx[i].l = l;
  53. stx[i].r = r;
  54. stx[i].build(1, 1, n);
  55. if (l == r)
  56. {
  57. locx[l] = i;
  58. return;
  59. }
  60. int mid = (l + r) / 2;
  61. build(i << 1, l, mid);
  62. build((i << 1) | 1, mid + 1, r);
  63. }
  64. //修改值
  65. void Modify(int x, int y, int val)
  66. {
  67. int tx = locx[x];
  68. int ty = locy[y];
  69. stx[tx].sty[ty].Min = stx[tx].sty[ty].Max = val;
  70. for (int i = tx; i; i >>= 1)
  71. for (int j = ty; j; j >>= 1)
  72. {
  73. if (i == tx && j == ty)continue;
  74. if (j == ty)
  75. {
  76. stx[i].sty[j].Min = min(stx[i << 1].sty[j].Min, stx[(i << 1) | 1].sty[j].Min);
  77. stx[i].sty[j].Max = max(stx[i << 1].sty[j].Max, stx[(i << 1) | 1].sty[j].Max);
  78. }
  79. else
  80. {
  81. stx[i].sty[j].Min = min(stx[i].sty[j << 1].Min, stx[i].sty[(j << 1) | 1].Min);
  82. stx[i].sty[j].Max = max(stx[i].sty[j << 1].Max, stx[i].sty[(j << 1) | 1].Max);
  83. }
  84. }
  85. }
  86. int queryMin(int i, int x1, int x2, int y1, int y2)
  87. {
  88. if (stx[i].l == x1 && stx[i].r == x2)
  89. return stx[i].queryMin(1, y1, y2);
  90. int mid = (stx[i].l + stx[i].r) / 2;
  91. if (x2 <= mid)return queryMin(i << 1, x1, x2, y1, y2);
  92. else if (x1 > mid)return queryMin((i << 1) | 1, x1, x2, y1, y2);
  93. else return min(queryMin(i << 1, x1, mid, y1, y2), queryMin((i << 1) | 1, mid + 1, x2, y1, y2));
  94. }
  95. int queryMax(int i, int x1, int x2, int y1, int y2)
  96. {
  97. if (stx[i].l == x1 && stx[i].r == x2)
  98. return stx[i].queryMax(1, y1, y2);
  99. int mid = (stx[i].l + stx[i].r) / 2;
  100. if (x2 <= mid)return queryMax(i << 1, x1, x2, y1, y2);
  101. else if (x1 > mid)return queryMax((i << 1) | 1, x1, x2, y1, y2);
  102. else return max(queryMax(i << 1, x1, mid, y1, y2), queryMax((i << 1) | 1, mid + 1, x2, y1, y2));
  103. }
  104. int main()
  105. {
  106. int T;
  107. scanf("%d", &T);
  108. int iCase = 0;
  109. while (T--)
  110. {
  111. iCase++;
  112. printf("Case #%d:\n", iCase);
  113. scanf("%d", &n);
  114. build(1, 1, n);
  115. for (int i = 1; i <= n; i++)
  116. for (int j = 1; j <= n; j++)
  117. {
  118. int a;
  119. scanf("%d", &a);
  120. Modify(i, j, a);
  121. }
  122. int q;
  123. int x, y, L;
  124. scanf("%d", &q);
  125. while (q--)
  126. {
  127. scanf("%d%d%d", &x, &y, &L);
  128. int x1 = max(x - L / 2, 1);
  129. int x2 = min(x + L / 2, n);
  130. int y1 = max(y - L / 2, 1);
  131. int y2 = min(y + L / 2, n);
  132. int Max = queryMax(1, x1, x2, y1, y2); //左下角右上角
  133. int Min = queryMin(1, x1, x2, y1, y2);
  134. int t = (Max + Min) / 2;
  135. printf("%d\n", t);
  136. Modify(x, y, t);
  137. }
  138. }
  139. return 0;
  140. }

KMP

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=1e5+5;
  4. char s1[maxn],s2[maxn];
  5. int Next[maxn];//最长前后缀
  6. /**串s中t出现的次数,s叫做主串,t叫做模式串**/
  7. void getNext(char s[])
  8. {
  9. int len = strlen(s);
  10. Next[0] = -1;
  11. int j = 0, k = -1;
  12. while(j < len)
  13. {
  14. if(k == -1 || s[j] == s[k])
  15. Next[++j] = ++k;
  16. else
  17. k = Next[k];
  18. }
  19. }
  20. /**
  21. 返回模式串t在主串s中首次出现的位置,返回的位置是从0开始的。
  22. **/
  23. int KMP_Index(char s[],char t[])
  24. {
  25. int i = 0, j = 0;
  26. int tlen = strlen(t);
  27. int slen = strlen(s);
  28. getNext(t);
  29. while(i < slen && j < tlen)
  30. {
  31. if(j == -1 || s[i] == t[j])
  32. {
  33. i++; j++;
  34. }
  35. else
  36. j = Next[j];
  37. }
  38. if(j == tlen)
  39. return i - tlen;
  40. else
  41. return -1;
  42. }
  43. /**
  44. 返回模式串t在主串s中出现的次数
  45. **/
  46. int KMP_Count(char s[], char t[])///可重叠
  47. {
  48. getNext(t);
  49. int cnt = 0;
  50. int i = 0, j = 0;
  51. int slen = strlen(s);
  52. int tlen = strlen(t);
  53. while(i < slen)
  54. {
  55. if(j == -1 || s[i] == t[j])
  56. {
  57. ++i;
  58. ++j;
  59. }
  60. else j = Next[j];
  61. if(j == tlen)
  62. {
  63. ++cnt;
  64. //j = 0; //要求不可重叠
  65. }
  66. }
  67. return cnt;
  68. }
  69. void KMP_Count2(char t[])///统计单串中从某个位置以前有多少重复的串
  70. {
  71. int tlen=strlen(t);
  72. for(int i=2;i<=tlen;++i)
  73. {
  74. int tmp=i-Next[i];
  75. if(i%tmp==0&&i/tmp>1)
  76. printf("\t位置:%d 个数:%d\n",i,i/tmp);
  77. }
  78. }
  79. int main()
  80. {
  81. while(scanf("%s%s",s1,s2)!=EOF)
  82. {
  83. printf("%d %d\n",KMP_Index(s1,s2),KMP_Count(s1,s2));
  84. }
  85. return 0;
  86. }

FFT求k次卷积

  1. int n, m, k;
  2. Complex x1[maxn], x2[maxn];
  3. bool p[maxn], q[maxn];
  4. void multiply(bool *p, int &n, bool *q, int m){
  5. int len = 1;
  6. while(len <= n + m) len <<= 1;
  7. for(int i = 0; i < len; i++) x1[i] = Complex(i <= n ? p[i] : 0, 0);
  8. for(int i = 0; i < len; i++) x2[i] = Complex(i <= m ? q[i] : 0, 0);
  9. fft(x1, len, 1);
  10. fft(x2, len, 1);
  11. for(int i = 0; i < len; i++) x1[i] = x1[i] * x2[i];
  12. fft(x1, len, -1);
  13. for(int i = 0; i <= n + m; i++) p[i] = x1[i].real() > 0.5;
  14. n += m;
  15. }
  16. int main()
  17. {
  18. scanf("%d%d", &n, &k);
  19. for(int i = 1; i <= n; i++){
  20. int x;
  21. scanf("%d", &x);
  22. q[x] = 1;
  23. }
  24. m = 1000;
  25. n = 0;
  26. p[0] = 1;
  27. while(k)
  28. {
  29. if(k & 1) multiply(p, n, q, m);
  30. if(k > 1) multiply(q, m, q, m);
  31. k >>= 1;
  32. }
  33. for(int i = 1; i <= n; i++) if(p[i]) printf("%d ", i); printf("\n");
  34. return 0;
  35. }

SG函数

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 1e5 + 5;
  4. int f[maxn], S[maxn];
  5. int sg[maxn];
  6. void getsg(int n, int m)
  7. {
  8. memset(sg, 0, sizeof(sg));
  9. for (int j, i = 1; i <= n; i++)
  10. {
  11. memset(S, 0, sizeof(S));
  12. for (j = 0; j <= m; j++)
  13. {
  14. if (i - f[j] >= 0)
  15. S[sg[i - f[j]]] = 1;
  16. }
  17. for (j = 0; j <= n; j++)
  18. if (!S[j])break;
  19. sg[i] = j;
  20. }
  21. }

矩阵系数

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ld double
  4. const int SZ = 1e5;
  5. int n;
  6. typedef vector<ld> vld;
  7. vld ps[2333];
  8. int pn = 0, fail[SZ];
  9. ld x[SZ], delta[SZ];
  10. int main()
  11. {
  12. scanf("%d", &n);
  13. for (int i = 1; i <= n; i++) scanf("%lf", x + i);
  14. for (int i = 1; i <= n; i++)
  15. {
  16. ld dt = -x[i];
  17. for (int j = 0; j < ps[pn].size(); j++)
  18. dt += x[i - j - 1] * ps[pn][j];
  19. delta[i] = dt;
  20. if (fabs(dt) <= 1e-7) continue;
  21. fail[pn] = i;
  22. if (!pn)
  23. {
  24. ps[++pn].resize(1);
  25. continue;
  26. }
  27. vld&ls = ps[pn - 1];
  28. ld k = -dt / delta[fail[pn - 1]];
  29. vld cur;
  30. cur.resize(i - fail[pn - 1] - 1); //trailing 0
  31. cur.push_back(-k);
  32. for (int j = 0; j < ls.size(); j++) cur.push_back(ls[j]*k);
  33. if (cur.size() < ps[pn].size()) cur.resize(ps[pn].size());
  34. for (int j = 0; j < ps[pn].size(); j++) cur[j] += ps[pn][j];
  35. ps[++pn] = cur;
  36. }
  37. for (unsigned g = 0; g < ps[pn].size(); g++)
  38. printf("%f ", ps[pn][g]);
  39. return 0;
  40. }

END

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