9.20题解
T1
考虑如果$k==0$,那么他就是一个裸的最长公共子序列,那么我们完全可以把$k$当作第$3$维,压进$dp$数组里,设$dp[i][j][k]$代表$A$串前$i$位和$B$串前$j$位匹配,修改了$k$次的最长公共子序列长度,多加一个转移方程就可以了,复杂度$O(n^3)$
1 #include<iostream> 2 #include<cstdio> 3 #define maxn 305 4 using namespace std; 5 int n,k,ans,i,j,l; 6 char a[maxn],b[maxn]; 7 int dp[maxn][maxn][maxn]; 8 int main() 9 { 10 //freopen("1.in","r",stdin); 11 //freopen("W.out","w",stdout); 12 scanf("%d%d",&n,&k); 13 scanf("%s%s",a+1,b+1); 14 for(i=1;i<=n;++i) 15 for(j=1;j<=n;++j) 16 for(l=0;l<=k;++l) 17 { 18 if(a[i]==b[j]) dp[i][j][l]=dp[i-1][j-1][l]+1; 19 ans=max(ans,dp[i][j][l]); 20 if(!l) continue; 21 dp[i][j][l]=max(dp[i][j][l],dp[i-1][j-1][l-1]+1); 22 ans=max(ans,dp[i][j][l]); 23 } 24 printf("%d\n",ans); 25 return 0; 26 }
T2
考场上并没有深入思考这道题,事实上吧,看了题解之后发现他非常非常的简单,一共要四个不同的点,我们可以枚举中间的两个点,假设分别为$x$和$y$,那么这两个点对答案的贡献就是$du[x]{\times}du[y]$,$du$里不包括对方,这样的话有一个问题就是我们会出现三元环,一个很好的解决方法是$bieset$,这玩意一般情况下都非常好用,得到包含这两个点的三元环的方法是用$bitset$记录和这个点有之间连边的点,然后把$x$和$y$的$bitset$与起来,一的个数就是三元环的数量,复杂度$O(\frac{n^3}{32})$
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<bitset> 5 #define maxn 2000 6 #define ll long long 7 using namespace std; 8 int n,js; 9 ll ans; 10 int du[maxn]; 11 char s[maxn]; 12 bitset <maxn> li[maxn]; 13 bitset <maxn> ls; 14 int main() 15 { 16 scanf("%d",&n); 17 for(int i=1;i<=n;++i) 18 { 19 scanf("%s",s+1); 20 for(int j=1;j<=n;++j) 21 if(s[j]=='1') {li[i][j]=1; du[i]++;} 22 } 23 for(int i=1;i<=n;++i) 24 for(int j=i+1;j<=n;++j) 25 if(li[i][j]) {ans+=(du[i]-1)*(du[j]-1); ls=li[i]&li[j]; ans-=ls.count();} 26 ans=ans*2; printf("%lld\n",ans); 27 return 0; 28 }
T3
由于二进制的特性,我们考虑拆点,考虑对于每一个权值,向所有它的子集连边权为$0$的边,一个数和他的子集做与运算得到的一定是他的子集,也可以给这个数往上补一,让每个点向他的权值连边权为$1$的边,权值向点连边权为$0$的边,反过来也可以,一个$0$一个$1$就行,然后就跑最短路就可以了
还有一个点就是如果把所有的边都建出来,边过于多了,所以说我们不真正建出来,在跑$dj$的时候,记得有这些边就可以
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<queue> 6 #define maxn 200200 7 #define maxm 300300 8 #define maxx 1300000 9 #define maxM 700700 10 #define inf 1061109567 11 using namespace std; 12 struct node{ 13 int di,pos; 14 bool operator < (const node &a)const 15 { 16 return a.di<di; 17 } 18 }; 19 int n,m,u,v,js; 20 int head[maxx],to[maxM],xia[maxM],w[maxM]; 21 int val[maxn],dis[maxx]; 22 priority_queue <node> s; 23 int lowbit(int x) 24 { 25 return x&(-x); 26 } 27 void add(int x,int y,int z) 28 { 29 to[++js]=y; xia[js]=head[x]; w[js]=z; head[x]=js; 30 } 31 void dj(int x) 32 { 33 memset(dis,0x3f,sizeof(dis)); 34 dis[x]=0; s.push((node){dis[x],x}); 35 while(s.size()) 36 { 37 node ls=s.top(); s.pop(); 38 if(ls.di!=dis[ls.pos]) continue; 39 for(int i=head[ls.pos];i;i=xia[i]) 40 { 41 int lss=to[i]; 42 if(dis[ls.pos]+w[i]<dis[lss]) 43 { 44 dis[lss]=dis[ls.pos]+w[i]; 45 s.push((node){dis[lss],lss}); 46 } 47 } 48 if(ls.pos>n) 49 { 50 int l=ls.pos-n-1; 51 for(int j=l;j>0;j-=lowbit(j)) 52 { 53 int lsx=l-lowbit(j),lss=lsx+n+1; 54 if(dis[ls.pos]<dis[lss]) 55 { 56 dis[lss]=dis[ls.pos]; 57 s.push((node){dis[lss],lss}); 58 } 59 } 60 } 61 } 62 } 63 int main() 64 { 65 scanf("%d%d",&n,&m); 66 for(int i=1;i<=n;++i) scanf("%d",&val[i]); 67 for(int i=1;i<=m;++i) {scanf("%d%d",&u,&v); add(u,v,1);} 68 for(int i=1;i<=n;++i) {add(i,val[i]+n+1,1); add(val[i]+n+1,i,0);} 69 dj(1); 70 for(int i=1;i<=n;++i) 71 { 72 if(dis[i]>=inf) printf("-1\n"); 73 else printf("%d\n",dis[i]); 74 } 75 return 0; 76 }