题解 CF1227G 【Not Same】

Owen_codeisking

2020-11-23 21:30:55

Solution

给出一个我自己都不会证的构造方法。 可以直观的想到:若我们每次取的集合都包含最小值且不相同,当最小值被删去后,再进入子问题,这样所有集合都不相同。 至多 $n+1$ 次操作,我们可以维护集合 $A$ 使得 $\max_A\le |A|+1$ 且取到上界最多一次。 这样可以分类讨论。 - 若 $\min A=\max A=|A|$,可以简单构造。 - 若 $\min A>1$,取当前没取过最小值的下标 $k$ (不包括最小值) 不选,其他值均选。 - 若 $\min A=1$,取当前没取过最小值的下标 $k$(不包括最小值) 不选,将一个 $1$ 和其他不为 $1$ 的数(除下标 $k$) $-1$。 可以看出,除了只有一种或两种本质不同的数的情况,最大值一定 $-1$。那么我们多选一次集合简单构造,使得 $\max A\le |A|$。 ```cpp #include <bits/stdc++.h> using namespace std; const int maxn=1005; int n,a[maxn],tot; vector<int> id; char s[maxn][maxn]; inline int check() { bool fl=0; vector<int> res; res.clear(); for(auto x:id) if(a[x]>0) res.push_back(x); else fl=1; id=res; return fl; } inline bool cmp(const int &x,const int &y) { return a[x]<a[y]; } inline void solve() { if(check()) return; sort(id.begin(),id.end(),cmp); bool fl=0; if(a[id[0]]>1 || a[id.back()]==1) { tot++; for(int i=1;i<=n;i++) s[tot][i]='0'; for(auto x:id) a[x]--,s[tot][x]='1'; fl=1; if(check()) return; } if(a[id[0]]==a[id.back()] && a[id[0]]==(int)id.size()-1) { for(auto x:id) { tot++; for(int i=1;i<=n;i++) s[tot][i]='0'; for(auto y:id) if(y!=x) a[y]--,s[tot][y]='1'; } check(); return; } int k; for(k=1;k<(int)id.size();k++) { if(a[id[0]]==1) break; tot++; for(int i=1;i<=n;i++) s[tot][i]='0'; for(auto y:id) if(y!=id[k]) a[y]--,s[tot][y]='1'; if(check()) return; } tot++; for(int i=1;i<=n;i++) s[tot][i]='0'; int y=(fl && a[id[k]]>1)?id[k]:0; for(auto x:id) if((x==id[0] || a[x]>1) && x!=y) a[x]--,s[tot][x]='1'; check(); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),id.push_back(i); while(!id.empty()) solve(); printf("%d\n",tot); for(int i=1;i<=tot;i++) printf("%s\n",s[i]+1); return 0; } ```