[牛客Wannafly挑战赛27D]绿魔法师

description

newcoder
给你一个空的可重集合\(S\)
\(n\)次操作,每次操作给出\(x\),\(k\),\(p\),执行以下操作:
\(opt\ 1\):在S中加入x。
\(opt\ 2\):输出
\[\sum_{y\in 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(n\sqrt x)\)地动态维护集合\(S\)\(i\)的倍数的数的个数\(p[i]\)

但是\(d\)的倍数和\(x\)\(gcd\)显然不一定是\(d\)

这里有一个可能比较简单的容斥做法:
考虑一开始\(gcd(x,y)==x\)的数的个数肯定是\(=p[x]\)的。
于是可以在\(p[i<x]\)中减掉\(p[x]\).
之后\(x\)的次大的约数也会变成正确答案;
这样逐级做下去即可求出我们需要的答案。

复杂度?
看起来是\(O(n\sqrt n\sqrt{\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\n",res);
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjfdf/p/9859161.html
今日推荐