Noip模拟58 2021.9.21(中秋祭&&换机房祭)
第一次在学校过中秋节,给家里人视频电话,感觉快回家了很开心,
然后还吃了汉堡喝饮料非常爽,颓废了一会儿还换了新机房,$Linux2.0$非常dei,少爷机也非常快,
发现好像测评机又成了老爷机,这就是信息领域的更新速度吗??
T1 Lesson5!
咕咕咕
T2 贝尔数
原先见过这种东西,但是这道题确实用不上。。。
考虑利用题目里面给的公式来做
1.$Bell_{n+1}=\sum_{k=0}^{n}C_{n}^{k}*Bell_{k}$
2.$Bell_{n+p}\equiv Bell_{n+1}+Bell_{n}(mod\ p) (p \in prime)$ Touchard同余公式
我们发现题目里面给的模数是几个质数相乘,那么考虑中国剩余定理,算出每个关于质数模数的答案然后合并
而考场上忘记如何打$CRT$在此止步了。。。更惨的是贪了一波空间不小心给爆内存了,直接送掉$50$分,可恶
以后开数组可要小心点,尤其是$longlong$的数组
关于质数模数的直接使用两个公式即可算出,然后为了快一点可以考虑使用矩阵加速转移,建出的转移矩阵需要满足同余公式的规律
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int NN=100,mod=95041567; 16 int T,n,m; 17 18 int B[NN],C[NN][NN]; 19 inline void work(){ 20 C[0][0]=1; 21 for(int i=1;i<=50;i++){ C[i][0]=C[i][i]=1; 22 for(int j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; 23 } B[0]=1; 24 for(int i=1;i<=50;i++) for(int j=0;j<i;j++) 25 B[i]=(B[i]+C[i-1][j]*B[j]%mod)%mod; 26 } 27 28 int mi[10]={0,31,37,41,43,47},M=95041567,x,y; 29 inline int EXgcd(int a,int b,int& x,int& y){ 30 if(!b){ x=1; y=0; return a;} 31 int gcd=EXgcd(b,a%b,x,y); 32 int t=x; x=y; y=t-y*(a/b); 33 return gcd; 34 } 35 36 namespace Matrix{ 37 int p[NN],c[NN][NN]; 38 struct Ma{ 39 int m[NN]; 40 int mm[NN][NN]; 41 }s[10]; 42 inline void mul(int a[NN],int b[NN][NN],int mo){ 43 memset(p,0,sizeof(p)); 44 for(int i=0;i<=mo-1;i++) 45 for(int j=0;j<=mo-1;j++) 46 p[i]=(p[i]+a[j]*b[j][i]%mod)%mod; 47 memcpy(a,p,sizeof(p)); 48 } 49 inline void mulself(int a[NN][NN],int mo){ 50 memset(c,0,sizeof(c)); 51 for(int i=0;i<=mo-1;i++) 52 for(int j=0;j<=mo-1;j++) 53 for(int k=0;k<=mo-1;k++) 54 c[i][j]=(c[i][j]+a[i][k]*a[k][j]%mod)%mod; 55 memcpy(a,c,sizeof(c)); 56 } 57 inline void prework(){ 58 for(int i=1;i<=5;i++) for(int j=0;j<mi[i];j++) s[i].m[j]=B[j]%mi[i]; 59 for(int i=1;i<=5;i++){ 60 int tmp=0; 61 for(int j=0;j<mi[i];j++){ 62 if(j==0) s[i].mm[mi[i]-1][j]=1; 63 else s[i].mm[tmp][j]=1,s[i].mm[tmp+1][j]=1,++tmp; 64 } 65 } 66 } 67 }using namespace Matrix; 68 69 namespace WSN{ 70 inline short main(){ 71 freopen("bell.in","r",stdin); 72 freopen("bell.out","w",stdout); 73 T=read(); work(); 74 while(T--){ 75 int n=read(),ans=0; 76 for(int i=1;i<=5;i++) memset(s[i].m,0,sizeof(s[i].m)),memset(s[i].mm,0,sizeof(s[i].mm)); 77 prework(); 78 for(int i=1;i<=5;i++){ 79 int cnt=n/(mi[i]-1); 80 while(cnt){ 81 if(cnt&1) mul(s[i].m,s[i].mm,mi[i]); 82 cnt>>=1; mulself(s[i].mm,mi[i]); 83 } 84 int Mi=M/mi[i],gcd=EXgcd(Mi,mi[i],x,y); 85 int ti=(x%mi[i]+mi[i])%mi[i]; 86 ans=(ans+s[i].m[n%(mi[i]-1)]*ti%mod*Mi%mod)%mod; 87 } 88 write(ans); 89 } 90 return 0; 91 } 92 } 93 signed main(){return WSN::main();}
T3 穿越广场
比较神仙的$AC$自动机+$dp$,考场上想到用自动机,但没想出如何设计$dp$,等于啥也不会
只有两个子串,那么我们设计四个状态$0,1,2,3$分别表示:
不包含任意一个串
包含第一个串
包含第二个串
包含两个串
那么设$f[i][j][k][l]$表示走到第$i$步,使用了$j$个$R$,走到了$trie$上的第$k$个节点,状态为$l$的方案数
那么边界是$f[0][0][root][0]=1$,终点是$\sum f[n+m][m][i][3]$
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int NN=105,mod=1e9+7; 16 int T,n,m; 17 char s[NN]; 18 queue<int> q; 19 namespace AC_JJ{ 20 int tot,tr[NN<<1][2],fail[NN<<1],tag[NN<<1]; 21 inline void insert(char *s,int id){ 22 int len=strlen(s+1),u=0; 23 for(int i=1;i<=len;i++){ 24 int ch=(s[i]=='D'?0:1); 25 if(!tr[u][ch]) tr[u][ch]=++tot; 26 u=tr[u][ch]; 27 } tag[u]|=id; 28 } 29 inline void getfail(){ 30 fail[0]=0; 31 for(int i=0;i<2;i++) 32 if(tr[0][i]) q.push(tr[0][i]),fail[tr[0][i]]=0; 33 else tr[0][i]=0; 34 while(!q.empty()){ 35 int u=q.front(); q.pop(); 36 if(tag[fail[u]]) tag[u]|=tag[fail[u]]; 37 for(int i=0;i<2;i++){ 38 if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]); 39 else tr[u][i]=tr[fail[u]][i]; 40 } 41 } 42 } 43 }using namespace AC_JJ; 44 int f[NN<<1][NN][NN<<1][4]; 45 namespace WSN{ 46 inline short main(){ 47 freopen("square.in","r",stdin); 48 freopen("square.out","w",stdout); 49 T=read(); 50 while(T--){ 51 m=read(); n=read(); tot=0; 52 memset(f,0,sizeof(f)); 53 memset(tr,0,sizeof(tr)); 54 memset(tag,0,sizeof(tag)); 55 memset(fail,0,sizeof(fail)); 56 scanf("%s",s+1); insert(s,1); 57 scanf("%s",s+1); insert(s,2); 58 getfail(); f[0][0][0][0]=1; 59 for(int i=0;i<n+m;i++){ 60 for(int j=0;j<=m;j++){ 61 if(j>i||i-j>n) continue; 62 for(int k=0;k<=tot;k++){ 63 for(int l=0;l<4;l++){ 64 (f[i+1][j ][tr[k][0]][l|tag[tr[k][0]]]+=f[i][j][k][l])%=mod; 65 (f[i+1][j+1][tr[k][1]][l|tag[tr[k][1]]]+=f[i][j][k][l])%=mod; 66 } 67 } 68 } 69 } 70 int ans=0; 71 for(int i=0;i<=tot;i++) ans=(ans+f[n+m][m][i][3])%mod; 72 write(ans); 73 } 74 return 0; 75 } 76 } 77 signed main(){return WSN::main();}
T4 舞动的夜晚
这是我见过的最长的图论题
拿到第五杀
考场上$yy$出了半正解,但是少连接了几条关键的边导致从$50->0$?
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int NN=1e5+5,inf=0x7fffffff,mod=1e9+7; 16 int n,m,TT; 17 struct bian{int u,v;}p[NN]; 18 struct SNOW{int fr,to,val,next;}e[NN<<1];int head[NN],rp=1; 19 inline void add(int x,int y,int z){ 20 e[++rp]=(SNOW){x,y,z,head[x]};head[x]=rp; 21 e[++rp]=(SNOW){y,x,0,head[y]};head[y]=rp; 22 } 23 24 int S,T,dis[NN],HD[NN],q[NN],h,t,maxnflow; 25 inline bool bfs(){ 26 memset(dis,0x3f,sizeof(dis)); 27 memcpy(head,HD,sizeof(head)); 28 q[h=t=1]=S; dis[S]=0; 29 while(h<=t){ 30 int x=q[h++]; 31 for(int i=head[x];i;i=e[i].next) if(e[i].val) 32 if(dis[e[i].to]>dis[x]+1) 33 dis[e[i].to]=dis[x]+1,q[++t]=e[i].to; 34 if(x==T) return 1; 35 }return 0; 36 } 37 inline int dfs(int x,int in){ 38 if(x==T) return in; 39 int rest=in,go; 40 for(int i=head[x];i;head[x]=i=e[i].next) if(e[i].val){ 41 int y=e[i].to,v=e[i].val; 42 if(dis[y]==dis[x]+1){ 43 go=dfs(y,min(rest,v)); 44 if(go) e[i].val-=go, e[i^1].val+=go, rest-=go; 45 else dis[y]=0; 46 }if(!rest) break; 47 }return in-rest; 48 } 49 inline int dinic(){ 50 int ans=0; 51 memcpy(HD,head,sizeof(HD)); 52 while(bfs()) ans+=dfs(S,inf); 53 return ans; 54 } 55 int tmp; 56 int pre[NN]; 57 namespace WSN{ 58 inline short main(){ 59 freopen("night.in","r",stdin); 60 freopen("night.out","w",stdout); 61 n=read(); m=read(); TT=read(); //二分图匹配,网络流 62 int tot=n+m; S=++tot; T=S+1; 63 for(int i=1;i<=TT;i++) p[i].u=read(),p[i].v=read()+n; 64 for(int i=1;i<=n;i++) add(S,i,1); 65 for(int i=1;i<=m;i++) add(i+n,T,1); 66 for(int i=1;i<=TT;i++) add(p[i].u,p[i].v,1); 67 // for(int i=1;i<=rp;i++) cout<<e[i].fr<<" "<<e[i].to<<" "<<e[i].val<<endl; 68 maxnflow=dinic(); 69 // cout<<maxnflow<<endl; 70 for(int i=1;i<=TT;i++){ 71 memset(head,0,sizeof(head)); rp=1; int ans=0; 72 int u=p[i].u,v=p[i].v; 73 for(int j=1;j<=n;j++) if(j!=u) add(S,j,1); 74 for(int j=1;j<=m;j++) if(j+n!=v) add(j+n,T,1); 75 for(int j=1;j<=TT;j++) if(j!=i&&p[j].v!=v&&p[j].u!=u) add(p[j].u,p[j].v,1); 76 ans=dinic(); if(ans+1<maxnflow) ++tmp,pre[tmp]=i; 77 } 78 write(tmp); 79 if(!tmp) return puts(""),0; 80 for(int i=1;i<=tmp;i++) write(pre[i],' '); 81 return 0; 82 } 83 } 84 signed main(){return WSN::main();}
这种挂分都已经不再意外了,可是还是很难受
挂了一百,只剩四十。。。。
暴力考虑到了正解就不远了。暴力是网络流的板子,每次按照题意新建一张图,再和初始的图去比较一下
如果最大流加一不到原来的最大流,那就是不好的一对舞蹈组合。
正解考虑先预处理出最大流,然后根据每条边流量的变化找到一组合法的二分图匹配,记录这些边为匹配边
再使用预处理时候的残量网络,跑一遍$Tarjan$,判断每一条边是否是合法边
合法边满足以下条件:1.不是匹配边;2.边$(i,j)$在一个$SCC$里面
然后用总边数减去合法边剩下的输出即可
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int NN=3e5+5,inf=0x7fffffff; 16 17 int n,m,TT; 18 struct bian{int u,v,id;}p[NN],match[NN],disma[NN]; 19 struct SNOW{ 20 int fr,to,val,next; 21 void print(){printf("fr=%lld to=%lld\n",fr,to);} 22 }e[NN<<1];int head[NN],rp=1; 23 24 inline void add(int x,int y,int z){ 25 e[++rp]=(SNOW){x,y,z,head[x]};head[x]=rp; 26 e[++rp]=(SNOW){y,x,0,head[y]};head[y]=rp; 27 } 28 inline void ADD(int x,int y){e[++rp]=(SNOW){x,y,0,head[x]};head[x]=rp;} 29 30 namespace Flow{ 31 int S,T,dis[NN],HD[NN],q[NN],h,t,maxnflow; 32 inline bool bfs(){ 33 memset(dis,0x3f,sizeof(dis)); 34 memcpy(head,HD,sizeof(head)); 35 q[h=t=1]=S; dis[S]=0; 36 while(h<=t){ 37 int x=q[h++]; 38 for(int i=head[x];i;i=e[i].next) if(e[i].val) 39 if(dis[e[i].to]>dis[x]+1) 40 dis[e[i].to]=dis[x]+1,q[++t]=e[i].to; 41 if(x==T) return 1; 42 }return 0; 43 } 44 inline int dfs(int x,int in){ 45 if(x==T) return in; 46 int rest=in,go; 47 for(int i=head[x];i;head[x]=i=e[i].next) if(e[i].val){ 48 int y=e[i].to,v=e[i].val; 49 if(dis[y]==dis[x]+1){ 50 go=dfs(y,min(rest,v)); 51 if(go) e[i].val-=go, e[i^1].val+=go, rest-=go; 52 else dis[y]=0; 53 }if(!rest) break; 54 }return in-rest; 55 } 56 inline int dinic(){ 57 int ans=0; 58 memcpy(HD,head,sizeof(HD)); 59 while(bfs()) ans+=dfs(S,inf); 60 return ans; 61 } 62 }using namespace Flow; 63 64 namespace Tarjan{ 65 int dfn[NN],low[NN],shu,scc_num,stk[NN],top,col[NN],tot[NN]; 66 bool vis[NN]; 67 inline void tarjan(int i){ 68 low[i]=dfn[i]=++shu; 69 stk[++top]=i,vis[i]=true; 70 for(int k=head[i];k;k=e[k].next){ 71 int j=e[k].to; 72 if(!dfn[j]) { 73 tarjan(j); 74 low[i]=min(low[j],low[i]); 75 } else if(vis[j]) low[i]=min(dfn[j],low[i]); 76 } 77 int k; 78 if(low[i]==dfn[i]){ 79 scc_num++; 80 do{ 81 k=stk[top--]; 82 col[k]=scc_num; 83 tot[scc_num]++; 84 vis[k]=false; 85 }while(k!=i); 86 } 87 } 88 }using namespace Tarjan; 89 90 int tmp,num,cnt; 91 int pre[NN]; 92 bool inq[NN],bin[NN]; 93 unordered_map<int,int> g[NN<<1]; 94 namespace WSN{ 95 inline short main(){ 96 freopen("night.in","r",stdin); 97 freopen("night.out","w",stdout); 98 n=read(); m=read(); TT=read(); 99 int Tot=n+m; S=++Tot; T=S+1; 100 for(int i=1;i<=TT;i++) p[i].u=read(),p[i].v=read()+n; 101 for(int i=1;i<=n;i++) add(S,i,1); 102 for(int i=1;i<=m;i++) add(i+n,T,1); 103 for(int i=1;i<=TT;i++) add(p[i].u,p[i].v,1); 104 maxnflow=dinic(); 105 // for(int i=1;i<=rp;i++) e[i].print(); 106 // cout<<maxnflow<<endl; 107 for(int i=2*(n+m)+2;i<=rp;i+=2) 108 if(!e[i].val) match[++num]=(bian){e[i].fr,e[i].to,(i-2*(n+m))/2},inq[e[i].fr]=inq[e[i].to]=1,g[e[i].fr][e[i].to]=1; 109 else disma[++cnt]=(bian){e[i].fr,e[i].to,(i-2*(n+m))/2}; 110 // for(int i=1;i<=num;i++) cout<<match[i].u<<" "<<match[i].v<<endl;cout<<endl; 111 memset(head,0,sizeof(head)); rp=1; 112 for(int i=1;i<=num;i++) ADD(match[i].v,match[i].u),++tmp,pre[tmp]=match[i].id; 113 for(int i=1;i<=cnt;i++) ADD(disma[i].u,disma[i].v); 114 for(int i=1;i<=n+m;i++){ 115 if(inq[i]){ 116 if(i<=n) ADD(i,S); 117 else ADD(T,i); 118 }else{ 119 if(i<=n) ADD(S,i); 120 else ADD(i,T); 121 } 122 } 123 // for(int i=1;i<=rp;i++) e[i].print(); 124 for(int i=1;i<=n+m+2;i++) if(!dfn[i]) tarjan(i); 125 // for(int i=1;i<=n+m+2;i++) cout<<col[i]<<endl; 126 for(int i=1;i<=TT;i++) 127 if(col[p[i].u]==col[p[i].v]&&!g[p[i].u][p[i].v]) ++tmp,pre[tmp]=i; 128 int ans=TT-tmp; 129 write(ans); 130 if(!ans) return puts(""),0; 131 for(int i=1;i<=tmp;i++) bin[pre[i]]=1; 132 for(int i=1;i<=TT;i++) if(!bin[i]) write(i,' '); 133 puts(""); 134 return 0; 135 } 136 } 137 signed main(){return WSN::main();}