「MCOI-05」魔仙
简化题意
构造一个长度为\(n\)的数组\(a_i\)
满足以下两个条件
\(\sum_1^{n}a_i=0\)
\(\prod_1^{n}a_i=n\)
根据第一个条件
其实很容易想到,构造一对相反数
再根据第二个条件
使这对相反数乘积为n
但光凭两个数根本不可能满足上述两种情况
一对相反数,只会有一个负数,而且乘积也为负数
所以很容易想到,再构造一对相反数,这对相反数存在的意义仅仅只是为把\(-n\)变为\(n\),所以为了不影响乘积 第二对相反数取\(1和-1\)
但会发现这仅仅只满足平方数
所以我们一般化一下
取\(n\)的任意两个因数\(a,b\) 使得\(a*b=n\)
此时第二对相反数\(c,d\)发挥更多的作用
为满足题意 所以 \(a+b+c+d=0\)
分类讨论
- \(a\)为负 \(b\)为正(令 \(|a|<|b|\))
那么此时需要 \(|b|-|a|\)个\(-1\) 这样目前的序列和则能为\(0\)
接下来就是 需要使乘积为n,现在整个序列乘积为\(n\)或\(-n\)
是\(n\)个话就直接添加\(1\)就可
是\(-n\)就要适量的\(-1\)使整个序列积为\(n\)
2.\(a,b\)同正(同负不过就是整个序列都乘\(-1\)而已)
先要\(a+b\)个\(-1\),然后适量添加\(+1\)或\(-1\)使序列和为\(0\),乘积为\(n\)
(这里讲下,免得后面的解释不太理解,两个同正的情况可以理解为两对相反数中抽出了两个正数)
思路到这就完了
可能有同学有疑惑?
1.无解的情况了??
\(n\) \(mod\) \(4!=0\)即为无解的情况
(非严格证明)
如果n为2的倍数则有可能出现 乘积为负数的情况
如果n为3的倍数则一定会出现 乘积为负数的情况
如果n为4的倍数则满足2不出现负数的情况且满足题意
(u1s1,其实可以不用特判,反正循环完了没输出应该就无解,没试过(逃)
- code
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int t;
int n;
const int maxn=1e6+10;
int prime[maxn];
bool isprime[maxn];
int cnt=0;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>n;
if(n%4) cout<<"ZFYAKIOI"<<endl;
else {
int a,b;
for(int i=2;i<=n;++i){
if(n%i==0) {
a=i,b=n/i;
if(a==b){//平方数
cout<<b<<" "<<(-1)*a<<" ";
for(int i=1;i<=(n-2)/2;++i) cout<<"-1 1 ";
cout<<endl;
break;
}
else if(n-2>=a+b && ((n-2+a+b)/2)%2==0) {//同正
cout<<a<<" "<<b<<" ";
for(int i=1;i<=a+b;++i) cout<<"-1 ";
for(int i=1;i<=(n-2-a-b)/2;++i) cout<<"1 -1 ";
cout<<endl;
break;
}
else if((n-2-(b-a)/2)%2==0 && (n-2-b+a)%2==0) {//一正一负
cout<<b<<" "<<(-1)*a<<" ";
for(int i=1;i<=b-a;++i) cout<<"-1 ";
for(int i=1;i<=(n-2-(b-a))/2;++i) cout<<"-1 1 ";
cout<<endl;
break;
}
/* else if((n-2-a-b)%2==0 && (n-2-a-b)%4==0){//同负
cout<<(-1)*a<<" "<<(-1)*b<<" ";
for(int i=1;i<=(a+b);++i) cout<<"1 ";
for(int i=1;i<=(n-2-a-b)/2;++i) cout<<"-1 1 ";
cout<<endl;
break;
} */
}
}
}
} return 0;
}