2 1 1 2 3
1 5
感觉出的不错。
题目是以前poj某道题的变种。POJ上面是n=n的特殊情况,所以直接求欧拉函数就OK了
这里n,m不一样,所以是转化为求1到n的每一个数,在1-m这段区间内所有互质的数的个数和
举个例子
n=5,m=10
答案
n=1时有10个与1互质
n=2时有5个与2互质
n=3时有7个与3互质
n=4时有5个与4互质
n=5时有8个与5互质
所以一共有35个
注意到,其实互质的本意就是指最大公约数为1
那么就是指没有公共的素因子。
---------
n=5,m=10的时候
ans=10/1+(10-10/2)+(10-10/3)+(10-10/2)+(10-10/5) (m-m/每一个数的质因子+m/两个质因子的积-m/三个质因子的积。。。。)
由于n的质因数个数不定。所以可以用容斥原理来计算重合部分
欧拉函数也要自己用快速预处理出来
我的代码:
#include<stdio.h> #include<algorithm> #include<vector> #define READ(x) (scanf("%I64d",&x)) #define COUT(x) (printf("%I64d\n",x)) using namespace std; typedef __int64 ll; ll prime[100005]; bool flag[100005]; ll phi[100005]; vector<ll>link[100005]; void init()//得到素数以及欧拉函数值 { ll i,j,num=0; phi[1]=1; for(i=2;i<=100000;i++) { if(!flag[i]) { prime[num++]=i; phi[i]=i-1; } for(j=0;j<num&&prime[j]*i<=100000;j++) { flag[prime[j]*i]=true; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(j=1;j<=100000;j++)//得到所有数包含的素因子 { ll tmp=j; for(i=0;prime[i]*prime[i]<=tmp;i++) { if(tmp%prime[i]==0) { link[j].push_back(prime[i]); tmp=tmp/prime[i]; while(tmp%prime[i]==0) tmp=tmp/prime[i]; } if(tmp==1) break; } if(tmp>1) link[j].push_back(tmp); } } ll dfs(ll x,ll b,ll now)//容斥原理 { ll i,res=0; for(i=x;i<link[now].size();i++) res=res+b/link[now][i]-dfs(i+1,b/link[now][i],now); return res; } int main() { init(); ll i,t,T,ans,n,m; READ(T); for(t=1;t<=T;t++) { ans=0; READ(n); READ(m); if(n>m) swap(n,m); for(i=1;i<=n;i++) ans=ans+m-dfs(0,m,i); COUT(ans); } return 0; }