TrickGCD
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 671 Accepted Submission(s): 257
* 1≤Bi≤Ai
* For each pair( l , r ) ( 1≤l≤r≤n ) , gcd(bl,bl+1...br)≥2
Each test case begins with an integer number n describe the size of array A .
Then a line contains n numbers describe each element of A
You can assume that 1≤n,Ai≤105
1 4 4 4 4 4
Case #1: 17
先说说这个题我学到了啥吧。
莫比乌斯反演的定义是正常我们求函数是G(X)=kF(X) 是知道F(X)求G(X) 然后这个反演就是知道G(X)求F(X) 反过来求
然后对于容斥原理 反演公式: F(n)=sigma(U(n/d)*G(d)) sigma是求和 这里U是一个函数,他是每一项 G(d) 的系数 U[x] = (-1)^r
如果 ei中(1<=i<=r)有一个数ei大于1 那么 U[x] = 0; 对于一个x这个数来说必定能分解因式为x=(p1^e1)*(p2^e2)...*(pr^er) 比
如2=2^1 有一个因子 6=2^1*3^1 有2个因子 比如12=2^2*3^1 那么U[6]=1 U[12]=0 U[2]=-1 然后
在计算 F(6)的时候,我们会用到 G(1) G(2) G(3) G(6)
我们考察者4个G
G(1) = F(1)
G(2) = F(1)+F(2)
G(3) = F(1)+F(3)
G(6) = F(1)+F(2)+F(3)+F(6)
当我们需要逆向有G得到F(n)时,只需要将一些 与 F(n) 有关的 G进行容斥!!!!! 最终组合得到F(n)!!!
比如 F(6) = G(6)-G(2)-G(3)+G(1)
这就得到了6所有的情况 所以 窝们就能得到ai时候所有的情况 就不会被容斥卡了
正解:先枚举gcd,然后每个位置有a[i]/d种方案,如果枚举1-n已经o(n)了,再求a[i]位置还有一个质因子的复杂度。 只能把a[i]/d相同的放在一起算,当然会有重复的情况,还得容斥一下 具体做法如下:
//china no.1
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <cstring>
#include <queue>
#include <list>
#include <stdio.h>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cctype>
#include <sstream>
#include <functional>
#include <stdlib.h>
#include <time.h>
#include <bitset>
using namespace std;
#define pi acos(-1)
#define endl '\n'
#define srand() srand(time(0));
#define me(x,y) memset(x,y,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0); cin.tie(0);
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,1,-1,-1,1};
const int dy[]={0,1,0,-1,-1,1,-1,1};
const int maxn=1e3+1e2;
const int maxx=1e5+1e2;
const double EPS=1e-7;
const LL mod=1e9+7;
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define W while
#define sgn(x) ((x) < 0 ? -1 : (x) > 0)
#define bug printf("***********\n");
inline int Scan()
{
int Res=0,ch,Flag=0;
if((ch=getchar())=='-')Flag=1;
else if(ch>='0' && ch<='9')Res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')Res=Res*10+ch-'0';
return Flag ? -Res : Res;
}
LL sum[maxx],p[maxx];
//p[x] 为gcd为x的个数
//第i个位置有a[i]/d种选择
//若a[i]/d=k贡献为k,则和它相同贡献有y=sum[kd,(k+1)d-1]个。
//累乘下来也就是k^y
//最后容斥减掉gcd为jx的部分(j>1)
int a[maxx];
int _pow(LL a,LL n)
{
LL ret=1;
while(n)
{
if(n&1) ret=ret*a%mod;
a=a*a%mod;
n>>=1;
}
return ret;
}
LL sb(LL x)
{
while(x<=0)
x+=mod;
}
int main()
{
int t,n;
// freopen( "in.txt" , "r" , stdin );
t=Scan();
for(int cas=1;cas<=t;cas++)
{
n=Scan();
me(sum,0);
me(p,0);
int maxc=0;
for(int i=1;i<=n;i++)
{
a[i]=Scan();
sum[a[i]]++;
maxc=max(maxc,a[i]);
}
for(int i=1;i<=maxc;i++)
sum[i]+=sum[i-1];
for(int i=maxc;i>=2;i--)
{
p[i]=1;
if(sum[i-1])//如果a[i]里有比当前d还小的数那么gcd为d的一定不存在
{
p[i]=0;//所以计算这一个d没有意义了
//例如 2 3 4 8 sum[i] 为0 1 2 3 3 3 3 4 下一位sum[7] 还有
//他的下一位还有 计算以8为gcd已经没有意义了
continue;
}
for(int j=i;j<=maxc;j+=i)
{
LL num=sum[min(maxc,i+j-1)]-sum[j-1];
LL x=j/i;
if(num)
p[i]=p[i]*_pow(x,num)%mod;
}
}
LL ans=0;
for(int i=maxc;i>=2;i--)
{
for(int j=i+i;j<=maxc;j+=i)
p[i]-=(p[j]-mod)%mod;
ans+=p[i];
ans%=mod;
}
ans%=mod;
printf("Case #%d: %lld\n",cas,ans);
}
//cerr << "run time is " << clock() << endl;
}