2024 杭电多校第六场
1005
状压dp,只不过压的是3进制。
模数有坑点,可能模完为0但是方案存在,也要输出。因此多开一个数组表示存不存在。
#include<bits/stdc++.h> using namespace std; const int N=500,K=10,LIM=6e4; const char ch[]={'A','B','C'}; int Mod; inline int add(int a,int b){return (a+=b)>=Mod?a-Mod:a;} int n,k,f[N+5][LIM+5]; bool g[N+5][LIM+5]; string op[N+5]; int _3[K+4]; vector<pair<string,int> >ans; int F(int x,char S) { if(S=='-') x=(x==0)?2:x-1; else if(S=='+') x=(x==2)?0:x+1; return x; } void Kafka() { cin>>n>>k>>Mod; for(int i=1;i<=n;++i) cin>>op[i],op[i]=op[i]; memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); f[0][0]=1,g[0][0]=1; for(int i=1;i<=n;++i) { for(int j=0;j<_3[k];++j) { if(!g[i-1][j]) continue; int v=0,tmp=j; for(int p=0;p<k;++p,tmp/=3) v+=F(tmp%3,op[i][p])*_3[p]; f[i][j]=add(f[i][j],f[i-1][j]); f[i][v]=add(f[i][v],f[i-1][j]); g[i][j]|=g[i-1][j]; g[i][v]|=g[i-1][j]; } } ans.clear(); for(int i=0;i<_3[k];++i) { if(!g[n][i]) continue; string s=""; for(int j=k-1,tmp=i;~j;--j,tmp/=3) s=s+ch[tmp%3]; ans.push_back(make_pair(s,f[n][i])); } sort(ans.begin(),ans.end()); for(int i=0,lim=ans.size();i<lim;++i) cout<<ans[i].first<<' '<<ans[i].second<<'\n'; } signed main() { ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); _3[0]=1;for(int i=1;i<=K;++i) _3[i]=_3[i-1]*3; int T; for(cin>>T;T--;) Kafka(); return 0; }
1007
容易发现答案可以递推,如果当前MEX为i,则一定不能选点权为i的点,但是点权为[0,i-1]的点都要选。
从i到i+1时要加入i点,而加入某点时相当于从该点开始一直往上级节点走,不断加入,直到遇到已经在联通块里的点。
累加答案时考虑当前联通块“边界”的那些点能否往外延申,预处理出dp[i]表示以i为根的子树选出一个连通块的方案。
#include<bits/stdc++.h> using namespace std; #define int long long const int P=998244353; const int N=1e5+505; inline int read() { int x=0;bool f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-'); for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return f?x:-x; } int n,sum; int a[N],dp[N],vis[N],fa[N],pos[N],ans[N]; vector<int> e[N]; int pow(int x,int y){ if (y==0) return 1; int tmp=pow(x,y/2); tmp=tmp*tmp%P; if (y&1) return tmp*x%P; else return tmp; } void dfs(int u){ vis[u]=1; int res=1; for (int i=0;i<e[u].size();i++){ int v=e[u][i]; if (vis[v]) continue; dfs(v); fa[v]=u; res=res*dp[v]%P; //printf("u=%lld v=%lld dp[v]=%lld res=%lld\n",u,v,dp[v],res); } dp[u]=res+1; vis[u]=0; } void add(int u){ for (int i=0;i<e[u].size();i++){ int v=e[u][i]; if (vis[v]) continue; if (v==fa[u]) continue; sum=sum*dp[v]%P; } } void merge(int u){ if (vis[u]) return; while(1){ vis[u]=1; add(u); if (vis[fa[u]]) break; u=fa[u]; } sum=sum*pow(dp[u],P-2)%P; } void test(){ for (int i=1;i<=n;i++) printf("dp[%lld]=%lld\n",i,dp[i]); for (int i=0;i<=n;i++) printf("ans[%lld]=%lld\n",i,ans[i]); } void work(){ n=read(); for (int i=1;i<=n;i++){ a[i]=read(); e[i].clear(); dp[i]=fa[i]=vis[i]=ans[i]=0; pos[a[i]]=i; } for (int i=1;i<n;i++){ int u,v; u=read(); v=read(); e[u].push_back(v); e[v].push_back(u); } dfs(pos[0]); int res=0; ans[0]=sum=dp[pos[0]]-1; vis[pos[0]]=1; for (int i=1;i<n;i++){ merge(pos[i]); ans[i]=sum; } for (int i=0;i<n;i++) res=(res+(ans[i]-ans[i+1]+P)%P*(i+1)%P)%P; //test(); cout << res << endl; } signed main() { int T; T=read(); while(T--) work(); return 0; }
1004
模拟题,有点细节。
首先肯定要保证上课时间和睡觉时间不重叠。
接下来只要维护不困的时间段即可。
#include<bits/stdc++.h> using namespace std; const int N =4e5+10; int n,m,cnt; int b[N],e[N],s[N],t[N]; struct node{ int val,op,se,en; }f[N]; bool cmp(node a,node b){ if(a.val!=b.val) return a.val<b.val; else return a.op<b.op; } void solve(){ cnt=0; cin>>n>>m; for(int i=1;i<=(n+m)*2;i++) f[i]=(node){0,0,0,0}; for(int i=1;i<=n;i++){ cin>>b[i]>>e[i]; f[++cnt]=(node){b[i],2,1,e[i]}; f[++cnt]=(node){e[i],2,-1,0}; } for(int i=1;i<=m;i++){ cin>>s[i]>>t[i]; f[++cnt]=(node){s[i],1,1,t[i]}; f[++cnt]=(node){t[i],1,-1,0}; } sort(f+1,f+cnt+1,cmp); int flag=1; for(int i=1;i<=cnt;i++){ if(f[i].op==1&&f[i].se==1){ if(f[i+1].op==1) continue; //f[i+1].op==2 if(f[i+1].se==-1){ if(f[i+1].val!=f[i].val) flag=0; if(f[i+2].op==2) flag=0; } } if(f[i].op==2&&f[i].se==1){ if(f[i+1].op==2) continue; // sleep if(f[i+1].se==-1) flag=0; else if(f[i+2].val!=f[i+1].val) { flag=0; } } } if(!flag) { cout<<"No"<<"\n"; return; } int l=-1,r=-1; for(int i=1;i<=cnt;i++){ if(f[i].op==2&&f[i].se==1) { // cout<<f[i].val<<" class "<<f[i].en<<"\n"; // cout<<l<<" "<<r<<"\n"; if(f[i].val>=l&&f[i].en<=r) { } else flag=0; } if(f[i].op==1&&f[i].se==1){ l=f[i].en; r=l+2*(f[i].en-f[i].val); // cout<<l<<" sleep "<<r<<"\n"; } } if(!flag) { cout<<"No"<<"\n"; } else cout<<"Yes"<<"\n"; } int main(){ ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t;cin>>t; while(t--){ solve(); } }
1003
模拟题
#include<bits/stdc++.h> using namespace std; const int N=1e5,dx[]={0,1,0,-1},dy[]={1,0,-1,0}; int n,ans; set<pair<int,int> >vis; void Kafka() { cin>>n; char s; vis.clear(); int x=0,y=0,d=0,tx,ty; ans=1; for(int i=1;i<=n;++i) { cin>>s; x+=dx[d],y+=dy[d]; if(i==1) tx=x,ty=y; if(s=='L') d=(d==0)?3:d-1; else if(s=='R') d=(d==3)?0:d+1; if(vis.find(make_pair(x,y))==vis.end()) vis.insert(make_pair(x,y)); else ans=min(ans,-1); } if(!(x==0&&y==0&&x+dx[d]==tx&&y+dy[d]==ty)) ans=min(ans,0); cout<<ans<<'\n'; } signed main() { ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); int T; for(cin>>T;T--;)Kafka(); return 0; }
1001
发现只能删度为2的点,且这种点不能超过5个,否则一定无解
那么暴力删点即可
#include<bits/stdc++.h> using namespace std; const int N = 2e5+5; int n,deg[N],mx=0,x[N],y[N],vis[N]; vector<int>e[N]; void dfs(int u,int p){ vis[u]=1; mx=max(mx,(int)e[u].size()); for(auto v:e[u]){ if(v==p) continue; dfs(v,u); } } void solve(){ cin>>n; for(int i=1;i<=n;i++) e[i].clear(),vis[i]=0,deg[i]=0; for(int i=1;i<n;i++) { cin>>x[i]>>y[i]; deg[x[i]]++;deg[y[i]]++; } set<int>s; for(int i=1;i<=n;i++){ if(deg[i]==2) s.insert(i); } if(s.size()>5||s.size()==0){ cout<<"No"<<"\n"; return; } for(auto v:s){ for(int i=1;i<=n;i++) e[i].clear(),vis[i]=0; // cout<<"?? "<<v<<"\n"; for(int i=1;i<n;i++){ if(x[i]==v||y[i]==v) continue; e[x[i]].push_back(y[i]); e[y[i]].push_back(x[i]); } set<int>num; for(int i=1;i<=n;i++){ if(vis[i]||i==v) continue; mx=0; dfs(i,0); num.insert(mx); // cout<<"mx "<<mx<<"\n"; } if( (*num.begin()) + *(num.rbegin()) ==n-3 ){ cout<<"Yes"<<"\n"; return; } } cout<<"No"<<"\n"; } int main(){ ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t;cin>>t; while(t--){ solve(); } }
1002
提供一种不同于正解的做法
重新定义菊花图:
菊花图首先是一棵树,其次存在一个点,它指向的点的度数都为1,剩下的都是度数为1的点。
那么在枚举删去某个点u时,只需要:
1.给u的邻点的度数-1(deg[u]--)
2.维护当前度数不为1的点的个数(代码里的non1)
3.维护 指向的点都为1度点的 点的个数(代码里的all1),实现时多开了一个cnt1[ ]表示某个点指向的1度点的个数,如果cnt1[u]==deg[u]且deg[u]>1,则该点是菊花图中心。
4.判定当前剩下的图是否为菊花图需要:all1==non1(说明度数不为1的点都是菊花图中心,则整个图一定是若干个菊花图)
实现时还有一些细节:
1.如果原图本来就是菊花图,把所有点都输出
2.如果原图有两个及两个以上的连通块不是菊花图,则无解
3.原图只有一个连通块不是菊花图,其他都是,这种情况有解,但要注意在枚举删去的点时,要把其他连通块里的点ban掉。
#include<bits/stdc++.h> using namespace std; const int N =2e5+5; int n,m,cnt=0,tot=0,mx=0,deg[N],vis[N],cnt1[N]; vector<int>e[N]; void dfs(int u,int p){ cnt++; vis[u]=1; tot+=e[u].size(); mx=max(mx,(int)e[u].size()); for(auto v:e[u]){ if(vis[v]) continue; dfs(v,u); } } int example; void solve(){ cin>>n>>m; for(int i=1;i<=n;i++){ deg[i]=0; cnt1[i]=0; vis[i]=0; e[i].clear(); } for(int i=1,u,v;i<=m;i++){ cin>>u>>v; e[u].push_back(v); e[v].push_back(u); deg[u]++,deg[v]++; } int G=0,pos=-1; for(int i=1;i<=n;i++){ if(!vis[i]){ cnt=0,tot=0,mx=0; dfs(i,0); if( cnt-1==tot/2 && mx==cnt-1) {}// 判断是否是菊花图 else { G++;pos=i; } } } if(G>=2){ cout<<-1<<"\n"; return; } else if(G==1){ for(int i=1;i<=n;i++) vis[i]=0; dfs(pos,0); set<int>s; int non1=0,all1=0; for(int i=1;i<=n;i++){ if(!vis[i]) continue; if(deg[i]>1) non1++; for(auto v:e[i]){ if(e[v].size()==1) cnt1[i]++; } if(cnt1[i]==(int)e[i].size()) all1++; } for(int i=1;i<=n;i++){ if(!vis[i]) continue; for(auto v:e[i]){ deg[v]--; } int add_all1=0; int add_non1=0; if(e[i].size()>1) add_non1=-1; set<int>newG; for(auto v:e[i]){ if(deg[v]==1){ for(auto to:e[v]){ if(to==i) continue; cnt1[to]++; if(cnt1[to]==deg[to]&°[to]>1) newG.insert(to); } add_non1--; } else { if(cnt1[v]==deg[v]&°[v]>1) newG.insert(v); } } add_all1=newG.size(); if(all1+add_all1==non1+add_non1) s.insert(i); for(auto v:e[i]) { deg[v]++; if(deg[v]==2){ for(auto to:e[v]){ if(to==i) continue; cnt1[to]--; } } } } if(s.size()==0) cout<<-1<<"\n"; else { for(auto v:s) { if(v!=(*s.rbegin()))cout<<v<<" "; else cout<<v; } cout<<"\n"; } } else { for(int i=1;i<=n;i++) { if(i!=n) cout<<i<<" "; else cout<<i; } cout<<"\n"; } } int main(){ // freopen("1002.in","r",stdin); // freopen("lys.out","w",stdout); ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t;cin>>t; while(t--){ example++; solve(); } } /* 9 6 5 4 6 4 4 9 8 7 7 9 7 2 */