问题可以这么理解——
构造一个$n+1$行$n$列的01矩阵$A$,满足:
1.第$i$列$n+1$个数的和为$a_{i}$
2.任意两行不完全相同
(对应关系:第$i$行第$j$列为1当且仅当第$i$次操作的集合包含$j$)
不妨将$a_{i}$从大到小排序,即$a_{1}ge a_{2}ge ...ge a_{n}$,此时构造方案:
初始矩阵为0,$forall 1le ile n$将第$i$列从第$i$行开始(包括第$i$行),下面$a_{i}$行填1(若行号大于$n+1$,则从第1行开始)
关于这一策略的正确性,即证明如此构造的矩阵$A$满足之前的两个条件:
对于第1个条件,由于$1le a_{i}le n$,显然成立
对于第2个条件,任取$i$和$j$(其中$1le i<jle n+1$),来证明第$i$行和第$j$行不完全相同——
取$(i,j]$中最小的$k$,满足$a_{k}+k>n+1$,对$k$分类讨论——
(1)不存在这样的$k$,必然有$a_{j}+jle n+1$,此时$A_{i,j}=0$而$A_{j,j}=1$
(2)$k=i+1$,此时$A_{i,i+1}=0$而$A_{j,i+1}=1$
(3)不为以上两种情况,那么$a_{k-1}+(k-1)le n+1$(否则显然取$k-1$)
注意到$a_{k-1}ge a_{k}$,即$a_{k-1}+(k-1)+1ge a_{k}+k$,前者$le n+2$,后者$>n+1$,即两者都为$n+2$,也即$a_{k-1}+(k-1)=n+1$,此时$A_{i,k-1}=0$而$A_{j,k-1}=1$
综上,即得证
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 pair<int,int>a[N]; 5 int n,ans[N][N]; 6 int main(){ 7 scanf("%d",&n); 8 for(int i=1;i<=n;i++){ 9 scanf("%d",&a[i].first); 10 a[i].first*=-1; 11 a[i].second=i; 12 } 13 sort(a+1,a+n+1); 14 for(int i=1;i<=n;i++){ 15 int x=a[i].second; 16 for(int j=i;j<i-a[i].first;j++) 17 if (j<=n+1)ans[j][x]=1; 18 else ans[j-(n+1)][x]=1; 19 } 20 printf("%d ",n+1); 21 for(int i=1;i<=n+1;i++){ 22 for(int j=1;j<=n;j++)printf("%d",ans[i][j]); 23 printf(" "); 24 } 25 }