[归并排序][枚举]JZOJ P3967 Counting Friends
题解
- 这题用的是比较暴力的方法
- 首先,我们知道该数字可以为额外的话,也就是其他的n个都可以匹配成需要那样、
- 那么就暴力枚举n+1个数,判断哪个可以为额外的数字
- 怎么匹配呢
- 其实有一种很简单的想法
- 就是从大到小排序,向后匹配(也就是往后的2~a[1]+1个都减1)
- 如果是可以匹配的数的话,这个方法一定是可以匹配的
- 那么我们考虑一下时间复杂度,每次一个数要O(n^2(n+n*log2n))
- 只能过6个点
- 那么快排的时间可以不可以更优呢?
- 考虑一下,减完之后的序列为0+有序的序列(2~a[1]+1)+有序的序列(a[1]+2~n)
- 有那种方法是可以直接在O(n)的时间下合并两个有序的序列呢?
- 显然归并排序
- 最后判断一波,输出,AC,perfect
代码
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 bool cmp(int x,int y){ return x>y; } 6 int n,a[510],x[510],y[510],tot,total,ans[510]; 7 int main() 8 { 9 scanf("%d",&n); 10 for (int i=1;i<=n+1;i++) scanf("%d",&a[i]); 11 for (int i=1;i<=n+1;i++) 12 { 13 tot=0; 14 for (int j=1;j<=n+1;j++) 15 if (i!=j) 16 x[++tot]=a[j]; 17 sort(x+1,x+n+1,cmp); 18 while (x[1]>0) 19 { 20 for (int j=2;j<=x[1]+1;j++) x[j]--; 21 int l1=2,r1=x[1]+1,l2=x[1]+2,r2=n; 22 tot=0; x[1]=0; 23 while (l1<=r1&&l2<=r2) 24 { 25 if (x[l1]<=x[l2]) y[++tot]=x[l2],l2++; 26 else y[++tot]=x[l1],l1++; 27 } 28 while (l1<=r1) y[++tot]=x[l1],l1++; 29 while (l2<=r2) y[++tot]=x[l2],l2++; 30 for (int j=1;j<=n;j++) x[j]=y[j]; 31 } 32 sort(x+1,x+n+1,cmp); 33 if (x[n]==0) ans[++total]=i; 34 } 35 printf("%d\n",total); 36 for (int i=1;i<=total;i++) printf("%d\n",ans[i]); 37 return 0; 38 }