CF1239D Catowice City
$solution:$
考虑类似于 $2-SAT$ 将必须选择的关系连边,$tarjan$ 后让最开始遍历的强连通分量为 $1$ ,因为 $dfs$ 的顺序易知这是正确的。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=1000001; int n,m,T,col[MAXN],sta[MAXN],num,dfn[MAXN],low[MAXN],Ans0[MAXN],Ans1[MAXN]; vector<int> vec[MAXN]; void Init(){ num=0;Ans0[0]=0,Ans1[0]=0; for(int i=0;i<=n;i++) vec[i].clear(); for(int i=0;i<=n;i++) col[i]=dfn[i]=low[i]=0; } void tarjan(int u){ dfn[u]=low[u]=++num;sta[++sta[0]]=u; int siz=vec[u].size(); for(int i=0;i<siz;i++){ int v=vec[u][i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); }else if(!col[v]) low[u]=min(low[u],low[v]); } if(dfn[u]==low[u]){ col[u]=++col[0]; while(sta[sta[0]]!=u){ col[sta[sta[0]]]=col[0]; sta[0]--; }sta[0]--; }return; } int main(){ // freopen("8.in","r",stdin); T=read(); while(T--){ n=read(),m=read(); Init(); for(int i=1;i<=m;i++){int u=read(),v=read();vec[u].push_back(v);} for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); if(col[0]==1){printf("No\n");continue;} for(int i=1;i<=n;i++){ if(col[i]==1) Ans0[++Ans0[0]]=i; else Ans1[++Ans1[0]]=i; } printf("Yes\n%d %d\n",Ans0[0],Ans1[0]); for(int i=1;i<=Ans0[0];i++) printf("%d ",Ans0[i]);printf("\n"); for(int i=1;i<=Ans1[0];i++) printf("%d ",Ans1[i]);printf("\n"); }return 0; }
CF1244F Chips
$solution:$
考虑若对于 $i$ 来说在 $i-1,i+1$ 有颜色相同的话,那么无论经过多少次操作都可以为本身颜色。
否则,与其相邻的是 $01$ 段,模拟一下即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=4000001; char str[MAXN]; int n,k,A[MAXN],B[MAXN],C[MAXN]; void print(int opt){opt?printf("W"):printf("B");} int main(){ n=read(),k=read(); scanf("%s",str+1); for(int i=1;i<=n;i++) A[i]=(str[i]=='W'); A[0]=A[n],A[n+1]=A[1]; for(int i=1;i<=n;i++) B[i]=(A[i-1]==A[i]||A[i]==A[i+1]),B[i+n]=B[i]; bool F=0;for(int i=1;i<=n;i++) F|=B[i]; if(!F){for(int i=1;i<=n;i++) print(A[i]^(k&1));printf("\n");return 0;} int ps=1;for(int i=1;i<=n;i++) if(B[i]) ps=i; for(int i=n+1;i<=2*n;i++){if(B[i]) ps=i;C[i-n]=i-ps;} for(int i=2*n;i>n;i--) if(B[i]) ps=i; for(int i=n;i>=1;i--){if(B[i]) ps=i;C[i]=min(C[i],ps-i);} for(int i=1;i<=n;i++){ if(B[i]) print(A[i]); else print(A[i]^(min(k,C[i])&1)); }printf("\n");return 0; }
CF1245F Daniel and Spring Cleaning
$solution:$
按维容斥后做简单数位 $dp$ 即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define int long long using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=30; int T,a,b,A[MAXN],B[MAXN],len,f[MAXN][2][2]; int dfs(int ps,int lim1,int lim2){ if(ps==-1) return 1; if(f[ps][lim1][lim2]!=-1) return f[ps][lim1][lim2]; int e1=(lim1==1)?A[ps]:1,e2=(lim2==1)?B[ps]:1,res=0; for(int i=0;i<=e1;i++) for(int j=0;j<=e2;j++){ if(i==1&&j==1) continue; res+=dfs(ps-1,lim1&&(i==A[ps]),lim2&&(j==B[ps])); } return f[ps][lim1][lim2]=res; } int calc(int x,int y){ if(x<0||y<0) return 0; memset(f,-1,sizeof(f)); len=29; for(int i=29;i>=0;i--) A[i]=(x&(1<<i))?1:0; for(int i=29;i>=0;i--) B[i]=(y&(1<<i))?1:0; return dfs(29,1,1); } signed main(){ // freopen("4.in","r",stdin); T=read(); while(T--){ int l=read(),r=read(); printf("%lld\n",calc(r,r)+calc(l-1,l-1)-2*calc(l-1,r)); } return 0; }
CF1245E Hyakugoku and Ladders
$solution:$
设 $f_{i,j}$ 表示从 $(i,j)$ 走到 $(1,1)$ 的期望步数,按题意模拟的转移即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=11; int M[N][N],fro[N*N]; double f[N*N]; int main(){ for(int i=1;i<=10;i++) for(int j=1;j<=10;j++){ if(i&1) M[i][j]=(i-1)*10+j; else M[i][j]=(i-1)*10+11-j; } double sum=0; f[1]=0;for(int i=2;i<=6;i++){ f[i]=(sum+6)/(i-1); sum+=f[i]; } for(int i=1;i<=10;i++){ for(int j=1;j<=10;j++){int x=read();fro[M[i][j]]=M[i-x][j];} } for(int i=7;i<=100;i++){ double s=0; for(int j=1;j<=6;j++) s+=min(f[i-j],f[fro[i-j]]); f[i]=s/6.0+1; } printf("%.10lf\n",f[100]);return 0; }
CF1249F Maximum Weight Subset
$solution:$
设 $f_{i,j}$ 表示以 $i$ 号节点为根的子树下距离 $i$ 最近的点至少为 $j$ 的方案数,枚举哪个要选即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=211; int n,k,f[N][N],head[N],cnt,val[N],son[N]; struct node{ int u,v,nex; }x[N<<1]; void add(int u,int v){ x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++; } void dfs(int u,int fath){ for(int i=head[u];i!=-1;i=x[i].nex){ if(x[i].v==fath) continue; dfs(x[i].v,u); } son[0]=0; for(int i=head[u];i!=-1;i=x[i].nex){ if(x[i].v==fath) continue; son[++son[0]]=x[i].v; } for(int i=0;i<=k;i++){ if(i==0){ f[u][0]=val[u]; for(int j=1;j<=son[0];j++) f[u][0]+=f[son[j]][k]; continue; } for(int j=1;j<=son[0];j++){ int res=f[son[j]][i-1]; for(int p=1;p<=son[0];p++){ if(j==p) continue; res+=f[son[p]][max(k-i,i-1)]; } f[u][i]=max(f[u][i],res); } }for(int i=k;i>=0;i--) f[u][i]=max(f[u][i],f[u][i+1]); } int main(){ memset(head,-1,sizeof(head)); n=read(),k=read(); for(int i=1;i<=n;i++) val[i]=read(); for(int i=1;i<n;i++){ int u=read(),v=read(); add(u,v),add(v,u); }dfs(1,0); printf("%d\n",f[1][0]);return 0; }