Codeforces - 1617C Paprika and Permutation
题意:给出一串数,每个操作可以选择一个数a和一个任意的模数x,将a换成a%x。问至少几次操作后可以将所有的数变成1-n的排列。
解:首先已经在1-n范围内的数不用动,考虑如何将其他数变成剩下的数,这显然要找个结论。由于多次取模和取一次可以有一样的结果,所以取一次就行了。
- 让a对任意数取模,得到的结果范围为[0,a/2)。
- 如果要把a变成b,那a%(a-b)显然是最可行的方案。如果a大于(a-b)的两倍,那就无法得到b了。
- 对于每一个要得到的b,如果a>=2*(a-b),显然a>=2*(a-(b+1)),即后续的b无法从a处转换,a这数没用了。但排列是从1-n一一对应的,这样一来就会空一个。
因此,从小到大将现有的数和目标检查,有一个不符合要求,输出-1即可。
代码:
#includeusing namespace std; #define ll long long #define maxx 200005 #define eps 0.000001 #define inf 0x3fffffff int n,m,k; int vis[maxx]={0}; int a[maxx]; signed main(){ int T; scanf("%d",&T); while(T--) { memset(vis,0,sizeof vis); memset(a,0,sizeof a); scanf("%d", &n); int cnt = 0; for (int i = 1; i <= n; i++) { int temp; scanf("%d", &temp); if (temp > 0 && temp <= n&&!vis[temp]) vis[temp]++; else a[++cnt] = temp; } sort(a + 1, a + 1 + cnt); int cnt2 = 0, ans = 0; int flag = 0; for (int i = 1; i <= n; i++) { if (vis[i]) continue; int temp=a[++cnt2]; if (temp>=(temp-i)*2) { flag = 1; break; } else ans++; } if (flag) printf("-1\n"); else printf("%d\n", ans); } return 0; }