[关闭]
@2368860385 2020-11-07T03:03:11.000000Z 字数 3782 阅读 190

六校联考第三场day2——2018.9.9

比赛总结

讲课录像:
T3~T6:https://www.bilibili.com/video/av31417889


10 + 40 + 1.5

后来参加的,T1读错了题,T2发现和马英杰以前出的一道题很像,然后最后也没想出,T3乱搞,时间很少了,没写出来。

T1

最长公共子串,可以允许修改k次(即可以k次失配),然后子串要求必须是连续的。读成了不要求是连续的,多读题!!!由于样例是连续的,往这里想了,但是没有再去读一读!!!

枚举一个起点,枚举另一个起点,往后一个一个走,如果不匹配了,直接修改就行,最多修改k次。

  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. char A[305], B[305];
  18. int main() {
  19. freopen("D.in","r",stdin);
  20. freopen("D.out","w",stdout);
  21. int n = read(), k = read(), ans = 0;
  22. scanf("%s", A + 1);
  23. scanf("%s", B + 1);
  24. for (int i=1; i<=n; ++i) {
  25. for (int j=1; j<=n; ++j) {
  26. int cnt = 0, p1 = i, p2 = j, now = 0;
  27. while (p1 <= n && p2 <= n) {
  28. if (A[p1] != B[p2]) {
  29. cnt ++;
  30. if (cnt > k) break;
  31. }
  32. p1 ++, p2 ++, now ++;
  33. }
  34. ans = max(ans, now);
  35. }
  36. }
  37. cout << ans;
  38. return 0;
  39. }

如果不连续的话,dp一下,f[i][j][k]第一个串到i,第二个串到j,修改了k次的最长长度。

  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 = 301;
  18. int f[N][N][N];
  19. char A[N], B[N];
  20. int main() {
  21. freopen("D.in","r",stdin);
  22. freopen("D.out","w",stdout);
  23. int n = read(), m = read();
  24. scanf("%s", A + 1);
  25. scanf("%s", B + 1);
  26. for (int i=1; i<=n; ++i) {
  27. for (int j=1; j<=n; ++j) {
  28. if (A[i] == B[j]) {
  29. for (int k=0; k<=m; ++k) {
  30. f[i][j][k] = max(f[i - 1][j][k], f[i][j - 1][k]);
  31. f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][k] + 1);
  32. }
  33. }
  34. else {
  35. for (int k=0; k<=m; ++k) {
  36. f[i][j][k] = max(f[i - 1][j][k], f[i][j - 1][k]);
  37. if (k >= 1) f[i][j][k] = max(f[i][j][k], max(f[i-1][j-1][k-1] + 1, max(f[i-1][j][k-1], f[i][j-1][k-1])));
  38. }
  39. }
  40. }
  41. }
  42. int Ans = 0;
  43. for (int i=1; i<=n; ++i)
  44. for (int j=1; j<=n; ++j)
  45. Ans = max(Ans, f[i][j][m]);
  46. cout << Ans;
  47. return 0;
  48. }
  49. */

T2

https://www.cnblogs.com/SovietPower/p/9626940.html

解释一下最后的容斥:
对于一个转移后得到的点集假设是这样的(为s|t的状态,设为) o o o o o o 一个圈表示一个数
考虑余集大小为1个转移到它的(就是从上面选一个为余集t,剩下的为初始点集s):
可能是这样的:

s1 : o o o o o
t1 : o
设上面的连向下面的边的条数为

s2 : o o o o o
t2 : o
设上面的连向下面的边的条数为

这时发现,多加了一些方案。
o o o o
设此状态为,即空着。
连向号点条数为,连向号点条数为。一定有一步转移是这样的:


现在
第一个式子是先选了3再选了2,第二个式子是先选了2再选了3,最后的结果是一样的,但是因为不同的顺序导致多加了一部分。
多加的部分:前面一个式子在选的过程中,这用1456选的2,然后后面的式子也是用选的3,那么这就是多了的方案数:。就是余集为2的方案数。
剩下的就是用1456选了3,然后用3选了2;和用1456选了2,用2选了3。
同样余集为3的时候在加上。

余集为2的方案数
s3 :o o o o
t3 : o o
当前就是:设上面的连向下面的边的条数为cnt3,方案数为

  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 mod = 1e9 + 7;
  18. const int N = 20;
  19. int mi[N * N], mp[N][N], g[N][(1 << 17) + 5], f[(1 << 17) + 5];
  20. int Calc(int s) {
  21. int res = 0;
  22. for (; s; s>>=1) res += (s & 1);
  23. return res;
  24. }
  25. int main() {
  26. freopen("E.in","r",stdin);
  27. freopen("E.out","w",stdout);
  28. int n = read(), m = read();
  29. mi[0] = 1;
  30. for (int i=1; i<=m; ++i) mi[i] = 1ll * mi[i - 1] * 2 % mod;
  31. for (int i=1; i<=m; ++i) mp[read() - 1][read() - 1] = 1;
  32. int S = (1 << n) - 1;
  33. for (int s=0; s<=S; ++s) {
  34. for (int i=0; i<n; ++i)
  35. if ((1 << i) & s)
  36. for (int j=0; j<n; ++j) g[j][s] += mp[j][i]; // j向余集s连向多少条边
  37. }
  38. f[0] = 1;
  39. for (int s=0; s<=S; ++s) { // 当前点集
  40. if (!f[s]) continue;
  41. int C = S ^ s;
  42. for (int t=C; t; t=(t-1)&C) { // 余集
  43. int sz = Calc(t), cnt = 0; // sz:余集大小,cnt:点集中所有点向余集连向的边数
  44. for (int i=0; i<n; ++i)
  45. if ((1 << i) & s) cnt += g[i][t];
  46. if (sz & 1) f[s|t] = (f[s|t] + 1ll * f[s] * mi[cnt] % mod) % mod;
  47. else f[s|t] = (f[s|t] - 1ll * f[s] * mi[cnt] % mod + mod) % mod;
  48. }
  49. }
  50. cout << f[S];
  51. return 0;
  52. }

T3

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