Paprika and Permutation
题目大意:
给你一个数列,你的目的是将这个数列通过操作变为一个1到n的排列,你可以进行的操作是选择这n个数中的一个数然后随便选择一个大于0的数x然后将选择的数列当中的数求模x的值代替原先的数列当中的数,我们的问题是最少多少次操作可以将这个数列变为一个排列,如若不能变为则输出-1
链接:CF_1617C
思路
- 这就是一个典型的思维题,既然要做到最少次数,我们既然要创造出1—n的排列,那么每一个数字我们都需要创造出来,大于2的数奇数都可以表示为它本身和1–x/2,偶数可以表示为1—x/2-1
- 或者我们换个角度 每个数只可能被大于它两倍的数创造出来,这里其实隐含着一个一 一 对应的关系(所需要的数值用它本身数值来代替就是用最小的数来创造出它,其余的数从小到大依次和排列中没有的数对应)
代码
#include<bits/stdc++.h>
using namespace std;
const int N =1e5+10;
typedef long long ll;
bool vis[N];
int t,n;
int main()
{
cin>>t;
while(t--)
{
cin>>n;
int res=0;
memset(vis,0,sizeof(vis));
ll w[N];
int idx=0;
for(int i=0;i<n;i++)
{
int x;
scanf("%d",&x);
if(x>=1&&x<=n&&!vis[x])
{
vis[x]=1;
}
else
{
w[idx++]=x;
}
}
sort(w,w+idx);
bool s=false;
idx=0;
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
if(w[idx++]<=2*i)
{
s=true;
break;
}
else
res++;
}
}
if(s)
{
puts("-1");
}
else
cout<<res<<endl;
}
return 0;
}