description
newcoder
给你一个空的可重集合(S)。
(n)次操作,每次操作给出(x),(k),(p),执行以下操作:
(opt 1):在S中加入x。
(opt 2):输出
[sum_{yin S}gcd(x,y)^k
]
data range
所有输入的数都是小于(10^5+1)的正整数。
solution
考场降智系列
对于一个(x),其(gcd(x,y))有(O(d(x))le O(sqrt x))个
这里(d(x))指(x)的约数个数
枚举(x)的约数(d),考虑如何算出(gcd(x,y)==d)的(y)的个数
我们可以(O(nsqrt x))地动态维护集合(S)内(i)的倍数的数的个数(p[i])。
但是(d)的倍数和(x)的(gcd)显然不一定是(d)。
这里有一个可能比较简单的容斥做法:
考虑一开始(gcd(x,y)==x)的数的个数肯定是(=p[x])的。
于是可以在(p[i<x])中减掉(p[x]).
之后(x)的次大的约数也会变成正确答案;
这样逐级做下去即可求出我们需要的答案。
复杂度?
看起来是(O(nsqrt nsqrt{sqrt n})=O(n^{frac{7}{4}}))的...
但是(=O(能过))。
Code
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define Cpy(x,y) memcpy(x,y,sizeof(x))
#define Set(x,y) memset(x,y,sizeof(x))
#define FILE "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ll;
typedef vector<int>VI;
//typedef long long ll;
typedef double dd;
const int N=2e5+10;
const int M=5e4+10;
const int mod=998244353;
const int base=113;
const dd eps=1e-8;
const int inf=1e9;
const ll INF=1ll<<60;
const ll P=100000;
#define mod (10007)
il int read(){
RG int data=0,w=1;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
return data*w;
}
il void file(){
srand(time(NULL)+rand());
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
}
inline int poww(int a,int b,int p){
RG int ret=1;
for(;b;b>>=1,a=1ll*a*a%p)
if(b&1)ret=1ll*ret*a%p;
return ret;
}
int n,cnt[N],pw[N],cal[N],top,f[N];VI fac[N];
inline void sieve(){
for(RG int i=1;i<=100000;i++)
for(RG int j=i;j<=100000;j+=i)
fac[j].push_back(i);
}
int main()
{
sieve();n=read();
for(RG int i=1,x,k,p,tmp,res,sz;i<=n;i++){
x=read();k=read();p=read();top=res=0;
sz=fac[x].size();
for(RG int j=0;j<sz;j++){
cnt[fac[x][j]]++;f[fac[x][j]]=cnt[fac[x][j]];
}
for(RG int j=sz-1;~j;j--)
for(RG int siz=fac[fac[x][j]].size(),k=siz-1;~k;k--)
if(fac[x][j]!=1&&fac[x][j]!=fac[fac[x][j]][k])
f[fac[fac[x][j]][k]]-=f[fac[x][j]];
for(RG int j=0;j<sz;j++)
{res+=1ll*f[fac[x][j]]*poww(fac[x][j],k,p)%p;if(res>=p)res-=p;}
printf("%d
",res);
}
return 0;
}