记录编号 98410 评测结果 AAAAAA
题目名称 [SPOJ 422] 转置更好玩 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 5.368 s
提交时间 2014-04-22 22:58:55 内存使用 0.32 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#define MOD 1000003
using namespace std;
typedef long long ll;
const int SIZEN=1010,SIZEP=60;
bool flag[SIZEN];
int prime[SIZEN]={0},pn=0;
int factr[SIZEP]={0};//底数
int facti[SIZEP]={0};//指数
int factv[SIZEP]={0};//值
int fn;
void getprime(int n){
	for(int i=2;i<=n;i++){
		if(!flag[i]){
			prime[pn++]=i;
			for(int j=i*i;j<=n;j+=i){
				flag[j]=true;
			}
		}
	}
}
int gcd(int a,int b){
	return !b?a:gcd(b,a%b);
}
void extend_gcd(ll a,ll b,ll &x,ll &y){//ax+by=(a,b)
	if(!b){x=1,y=0;}
	else{
		extend_gcd(b,a%b,y,x);
		y-=a/b*x;
	}
}
int pow2[33]={0};
void initpow(void){
	pow2[0]=2;
	for(int i=1;i<32;i++) pow2[i]=1ll*pow2[i-1]*pow2[i-1]%MOD;
}
int quickpow2(int n){
	int ans=1;
	for(int i=0;n>0;n>>=1,i++){
		if(n&1) ans=1ll*ans*pow2[i]%MOD;
	}
	return ans;
}
void getfact(int n){//做分解
	fn=0;
	for(int i=0;i<pn;i++){
		if(n%prime[i]==0){
			factr[fn]=prime[i];
			facti[fn]=0;
			factv[fn]=1;
			while(n%prime[i]==0){
				facti[fn]++;
				factv[fn]*=prime[i];
				n/=prime[i];
			}
			fn++;
		}
	}
	if(n>1){//本身是一个大素数
		factr[fn]=n;
		facti[fn]=1;
		factv[fn]=n;
		fn++;
	}
}
void DFS(int &ans,int g,int phi,int dep){//gcd值是g的情况
	//则情况数量为phi((a+b)/g),这里的phi是Euler函数
	//但变量phi只储存phi((a+b)/g)的表达式中只涉及少于dep的素因子的部分的结果
	//例如,如果最终的Euler函数值是((2-1)*(2^3))*((5-1)*(5^6))*((7-1)*(7^10)),那么phi有可能仅仅是((2-1)*(2^3))
	if(dep==fn){
		//如果这里情况中的某个循环一次走x步,那么(x,a+b)=g
		//可以看到,对每个x,合法的"保持不变"染色个数是2^g,一共phi*2^g个
		ans=(1ll*phi*quickpow2(g)+ans)%MOD;
		return;
	}
	int i=0,p=factv[dep];
	while(i<=facti[dep]){
		DFS(ans,factv[dep]/p*g,phi*(p-p/factr[dep]),dep+1);
		//factv[dep]/p*g是把当前的g值乘上当前枚举的素因子的一个幂
		//具体地说,是乘上factr[dep]^i
		//于是涉及factr[dep]的phi值应当是phi*(factr[dep]-1)*factr[dep]^(facti[dep]-i-1)(根据Euler函数的积性)
		i++,p/=factr[dep];
	}
}
int calc(int a,int b){
	if(!a||!b) return 0;
	int g=gcd(a,a+b);
	getfact((a+b)/g);
	int ans=0;
	DFS(ans,g,1,0);//一"小块"的长度是g,因此合法的置换一次都要走g的倍数
	ll x,y;
	extend_gcd((a+b)/g,MOD,x,y);//此处求逆元,因为要除以总的置换数量(a+b)/g
	x%=MOD;
	ans=((quickpow2(a+b)-x*ans)%MOD+MOD)%MOD;
	return ans;
}
int main(){
	freopen("transp2.in","r",stdin);
	freopen("transp2.out","w",stdout);
	initpow();
	getprime(SIZEN-1);
	int T;
	scanf("%d",&T);
	while(T--){
		int a,b;
		scanf("%d%d",&a,&b);
		printf("%d\n",calc(a,b));
	}
	return 0;
}