洛谷P3599 Koishi Loves Construction 构造 逆元

题意:Task1:试判断能否构造并构造一个长度为n的排列,满足其n个前缀和在模nn的意义下互不相同

Task2:试判断能否构造并构造一个长度为n的排列,满足其n个前缀积在模n的意义下互不相同
题解: 不妨写个暴力观察一下规律。

对于T1 n一定是在排列的最前面,因为任意数+n%n的答案一定一样
奇数都没有解,对于偶数尝试构造数列(可以通过dfs搜出几个答案很容易看出这一组数列)
n , 1 , n − 2 , 3 , n − 4.... n,1,n-2,3,n-4.... n,1,n2,3,n4....
这个数列很显然是满足条件的
T2:简单分析可得出n必须放在末尾,1必须放在首位
n为质数特例有1,4
同样用暴力dfs观察规律,对于前缀积模n满足条件:
1 , 2 , 3 , 4 , . . . . n − 1 , 0 1,2,3,4,....n-1,0 1,2,3,4,....n1,0
有等式:
2 ∗ a n s ( 2 ) ≡ 3 ( m o d n ) 2*ans(2)\equiv3(modn) 2ans(2)3(modn)
a n s ( x ) ≡ x + 1 x ( m o d n ) ans(x)\equiv\frac{x+1}{x}(mod n) ans(x)xx+1(modn)
所以就是构造模n下的序列:
1 , 2 1 , 3 2 . . . . n n − 1 1,\frac{2}{1},\frac{3}{2}....\frac{n}{n-1} 1,12,23....n1n
由于n为质数(除1,4之外)所以用费马小定理求逆元就行了

#include<bits/stdc++.h>
#define ll long long 
const int MAXN=1e6+10;
const int M=1e6;
using namespace std;
bool vis[MAXN];
int ans[MAXN];
int sum[110];
int flag[110];
int T,X,num;
ll prime[MAXN],n;
bool isPrime[MAXN];
ll pow_mod(ll a,ll b,ll  MOD){
	int ans=1;
	while(b){
		if(b&1) ans=ans*a%MOD;
		b>>=1;a=a*a%MOD;
	}
	return ans;
}
void dfs(int num){
	if(num==n+1){
		memset(flag,0,sizeof flag);
		sum[0]=1;
		for(int i=1;i<=n;i++){
			sum[i]=sum[i-1]*ans[i]%n;
			flag[sum[i]%n]++;
		}
		for(int i=0;i<n;i++){
			if(flag[i]!=1)	return ;
		}
		cout<<endl;
		
		for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
		cout<<endl;
		for(int i=1;i<=n;i++) cout<<sum[i]<<" ";
		cout<<endl; 
		return ;
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			ans[num]=i;vis[i]=1;
			dfs(num+1);
			ans[num]=0;vis[i]=0;
		}
	}
	
}
void init(int x){
	num=0;memset(vis,0,sizeof vis);
	for(int i=2;i<=x;i++){
		if(!vis[i]) prime[++num]=i;
		for(int j=1;prime[j]*i<=x && j<=num;j++){
			vis[i*prime[j]]=1;
			if(!(i%prime[j])) break;
			
		}
	}
	memset(isPrime,0,sizeof isPrime);
	for(int i=1;i<=num;i++) isPrime[prime[i]]=1; 
} 


int main(){
	ios::sync_with_stdio(false);
	init(1e6);
	cin>>X>>T;
	if(X==1){
		while(T--){
			cin>>n;
			if((n&1)&&(n^1)) cout<<"0"<<endl;
			else {
				cout<<"2 ";
				ans[1]=n;
				ans[2]=1;
				for(int i=4;i<=n;i+=2) ans[i]=ans[i-2]+2;
				for(int i=3;i<=n;i+=2) ans[i]=ans[i-2]-2; 
				for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
				cout<<endl;
			}
		}
	}else{
		while(T--){
			cin>>n;
			if(n==1 || n==4 || isPrime[n]) {
				
				cout<<"2 ";
				if(n==1) {
					cout<<"1"<<endl;continue;
				}
				if(n==4) {
					cout<<"1 3 2 4"<<endl;continue;
				}
				ans[1]=1;ans[n]=n;
				for(int i=2;i<=n-1;i++) ans[i]=(i%n)*(pow_mod(i-1,n-2,n)%n)%n;
				for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
				cout<<endl; 
			}else cout<<"0"<<endl;
			
		}
	} 
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值