CF 612 div1
三道大水题
A
题解
dp,用 $ f[i][j][0/1]$ 表示到第 \(i\) 个空格且一共填了 \(j\) 个奇数,末尾为奇数或偶数的最小值
转移见代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define ll long long using namespace std; int read() { int k=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f; } int n,x,y,a[500],f[105][105][2]; int tot,pos[500]; int main() { n=read(); y=n/2;x=n-y; for(int i=1;i<=n;i++) { a[i]=read(); if(a[i]&1) x--; else if(a[i]!=0) y--; else pos[++tot]=i; } memset(f,0x3f,sizeof(f)); if(pos[1]==1) { f[1][1][1]=f[1][0][0]=0; } else { f[1][1][1]=(a[pos[1]-1]&1)^1; f[1][0][0]=(a[pos[1]-1])&1; } for(int i=2;i<=tot;i++) for(int j=0;j<=x&&j<=i;j++) { if(pos[i]-1!=pos[i-1]) { f[i][j][0]=min(f[i-1][j][0]+(a[pos[i-1]+1]&1),f[i-1][j][1]+((a[pos[i-1]+1]&1)^1))+(a[pos[i]-1]&1); if(j) f[i][j][1]=min(f[i-1][j-1][0]+(a[pos[i-1]+1]&1),f[i-1][j-1][1]+((a[pos[i-1]+1]&1)^1))+((a[pos[i]-1]&1)^1); } else { f[i][j][0]=min(f[i-1][j][0],f[i-1][j][1]+1); if(j) f[i][j][1]=min(f[i-1][j-1][1],f[i-1][j-1][0]+1); } } if(pos[tot]!=n) { f[tot][x][1]+=(a[pos[tot]+1]&1)^1; f[tot][x][0]+=a[pos[tot]+1]&1; } int ans=min(f[tot][x][0],f[tot][x][1]); if(!tot) ans=0; for(int i=1;i<n;i++) if(a[i]!=0&&a[i+1]!=0) ans+=((a[i]&1)^(a[i+1]&1)); printf("%d\n",ans); return 0; }
B
题解
从叶子向根部确定值即可,如果某节点的 \(c[i]\) 大于它所有子树的节点,就输出 NO。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define ll long long using namespace std; int read() { int k=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f; } const int N=5005; int n,m,sum,a[N],b[N],c[N]; int tot,to[N],nextt[N],head[N]; bool cmp(int x,int y) { return a[x]<a[y]; } void add(int a,int b) { to[++tot]=b; nextt[tot]=head[a]; head[a]=tot; } void get(int u) { b[++sum]=u; for(int i=head[u];i;i=nextt[i]) get(to[i]); } void dfs(int u) { for(int i=head[u];i;i=nextt[i]) dfs(to[i]); sum=0; for(int i=head[u];i;i=nextt[i]) { get(to[i]); } if(c[u]>sum) {puts("NO");exit(0);} if(!head[u]) { m++; a[u]=m*N+1; return; } sort(b+1,b+1+sum,cmp); if(c[u]==0) a[u]=a[b[1]]-1; else if(a[b[c[u]+1]]-a[b[c[u]]]>1||c[u]==sum) a[u]=a[b[c[u]]]+1; else { a[u]=a[b[c[u]]]+1; for(int i=c[u]+1;i<=sum;i++) a[b[i]]++; } } int main() { int x,rt; n=read(); for(int i=1;i<=n;i++) { x=read(); if(x) add(x,i); else rt=i; c[i]=read(); } dfs(rt); puts("YES"); for(int i=1;i<=n;i++) printf("%d\n",a[i]); return 0; }
C
题解
求 \(s[1...n]\) 和 \(s[2...n]\) 的所有字串,多出来的 \(n\) 个字串就是 \(s[1..i](1≤i≤n)\) ,我们很容易就求出原字符串了
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<set> #define ll long long using namespace std; int read() { int k=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f; } const int N=205; int n,a[26],b[26]; string str,ss[N]; char ans[N]; multiset<string> s; bool cmp(string a,string b) { return a.size()<b.size(); } int main() { cin>>n; if(n==1) { cout<<"? 1 1\n"; fflush(stdout); cin>>ans[1]; cout<<"! "<<ans[1]<<endl; fflush(stdout); return 0; } else { cout<<"? 1 "<<n<<endl; fflush(stdout); for(int i=1;i<=n*(n+1)/2;i++) { cin>>str; sort(str.begin(),str.end()); s.insert(str); } cout<<"? 2 "<<n<<endl; fflush(stdout); for(int i=1;i<=n*(n-1)/2;i++) { cin>>str; sort(str.begin(),str.end()); s.erase(s.find(str)); } n=0; for(multiset<string>::iterator i=s.begin();i!=s.end();i++) ss[++n]=*i; sort(ss+1,ss+1+n,cmp); for(int i=1;i<=n;i++) { memset(a,0,sizeof(a)); for(int j=0;j<ss[i].size();j++) a[ss[i][j]-'a']++; for(int j=0;j<26;j++) if(a[j]-b[j]) ans[i]='a'+j; memcpy(b,a,sizeof(a)); } cout<<"! "<<ans+1<<endl; fflush(stdout); return 0; } }
来源:https://www.cnblogs.com/waing/p/12209884.html