P8880 无知时诋毁原神
题意简述:
给定一个\(0\sim n-1\) 的排列 \(c\)。构造两个同样为 \(0\sim n-1\) 的排列的 \(a,b\),满足 \(\forall i\in[1,n],c_i=(a_i+b_i)\bmod n\)。如果不存在,请输出 \(-1\)。
题解
构造题考脑子……
模 \(n\) 在数据范围下等价于是让我们求出两个序列 \(a,b\) 使得 \(a_i+b_i=c_i+n或c_i\)。由于每一个 \(i\) 相互独立,所以实际上我们不需要管 \(c\) 的顺序,我们只考虑拼出这 \(n\) 个数即可。
首先直觉告诉我们,方案数应该是有不少的,但应该有一种固定的构造方案。并且拼出大于等于 \(n\) 的数与小于 \(n\) 的数的个数应该是比较均衡的。我们来先玩玩小数据看看规律。
\(n=3\):
\(a\):0,2,1。
\(b\):0,2,1。
\(n=5\):
\(a\):0,3,1,4,2。
\(b\):0,3,1,4,2。
\(n=7\):
\(a\):0,4,1,5,2,6,3。
\(b\):0,4,1,5,2,6,3。
\(n=2,4,6\)。无解
我们发现,在 \(3,5,7\) 三种情况,我们都可以构造出一组 \(a,b\) 完全一样的数据。下面我们来证明当 \(n\) 为奇数的时候存在这样一种构造方案。
首先证明充分性:\(a,b\) 完全一样,意味着拼出来的数都是偶数,那么小于 \(n\) 的偶数只有 \(\left\lfloor\frac{n}{2}\right\rfloor\) 个,并取 \(0,2,4……n-1\)。
这里就用去了 \(0\sim \left\lfloor\frac{n}{2}\right\rfloor\),考虑剩下的数 \(\left\lceil\frac{n}{2}\right\rceil\sim n-1\)。
将这些数全部减去 \(\frac{n}{2}\)(注意这里带个小数)就得到了两数之和最终减去 \(n\) 的结果。此时剩下的数就取 \(0.5,1.5,2.5,3.5……\frac{n-2}{2}\),这些数加上就得到了所有的奇数 \(1,3,5,7……\),故在 \(n\) 为奇数的时候这个方案是优秀的。
然后再来思考一下偶数的情况,为什么我们试三个偶数都是无解呢?
由于刚刚的奇数情况,我们用到了奇偶性的思想,考虑再从奇偶性的角度考虑证明偶数无解或者一种优秀的构造方案。
由于是偶数,\(a_i+b_i \bmod n\) 的奇偶性是不变的。那么奇数就只能由一奇一偶来拼出来。由于构造前后奇数个数不变,所以我们就用去了 \(a\) 中所有的奇数与 \(b\) 中所有的偶数,剩下的数也只能奇偶拼出奇数,故这是错误的,偶数情况无解。
故就得到了本题代码:
int n,a[5000005],b[5000050],vis[5000500];
int main(){
cin>>n;
for(int i=0;i<n;i++)b[(i<<1)%n]=i;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]=b[a[i]];
}
for(int i=1;i<=n;i++){
if(vis[a[i]]){
puts("-1");
return 0;
}
vis[a[i]]=1;
}
for(int i=1;i<=n;i++)cout<<a[i]<<" ";
puts("");
for(int i=1;i<=n;i++)cout<<a[i]<<" ";
return 0;
}
标签:原神,诋毁,frac,奇数,int,题解,构造,偶数,sim
From: https://www.cnblogs.com/oierpyt/p/16950414.html