【NOIP2017提高A组冲刺11.6】项链

来源:互联网 发布:企业网络规划方案 编辑:程序博客网 时间:2024/05/17 23:52

Description

给一个n个点的环染m种颜色,有3种操作,分别为旋转、翻转和把所有颜色编号+1
如果两个方案在经过任意次操作之后等价了这两个方案就是等价的
求所有本质不同的染色方案数
n,m<=1e18,保证n,m逆元存在

Solution

burnside裸题,但是多了一个颜色操作
把颜色操作也视为置换,考虑他对经典的两种置换的影响
对于旋转,我们每一组的循环节长度为n/(i,n)
如果它在+把所有颜色d(0<=d< m)后能变回它自己它就是一个不动点
那么循环节种的每一个元素在模m意义下都比上一个元素大d
能变回原样就是n/(i,n)d≡ 0 mod m
经过一些简单的数论推导我们可以得出d有(m,n/(i,n))种取值
于是我们的旋转就变成了

i=1nm(i,n)(m,n(i,n))

同理可以发现翻转时我们只有当对称轴不经过点时会产生长度为2的循环节
于是翻转可以O(1)解决
考虑旋转的式子,枚举n的因数i
i|nmi(m,ni)j=1n[gcd(j,n)=i]

i|nmi(m,ni)φ(ni)

如果我们能对n分解质因数那么这道题就做完了
发现n可以达到10^18,于是我们需要用Pollard_Rho来分解
然后就做完了

Code

#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)using namespace std;typedef long long ll;const int Mo=998244353,S=3;ll mult(ll x,ll y,ll Mo) {    x%=Mo;y%=Mo;    ll tmp=(ll)((long double)x*y/Mo+1e-8)*Mo;    return (x*y-tmp+Mo)%Mo;}ll pwr(ll x,ll y,ll Mo) {    ll z=1;x%=Mo;y%=(Mo-1);    for(;y;y>>=1,x=mult(x,x,Mo))        if (y&1) z=mult(z,x,Mo);    return z;}ll gcd(ll x,ll y) {    if (!x) return 1;    if (x<0) return gcd(-x,y);    return y?gcd(y,x%y):x;}ll n,m,ans,nn,mm,invm;ll pri[70],a[20];int tot,cnt,b[20],tmp;bool check(ll a,ll n,ll x,ll t) {    ll res=pwr(a,x,n),lst=res;    fo(i,1,t) {        res=mult(res,res,n);        if (res==1&&lst!=1&&lst!=n-1) return 1;        lst=res;    }    if (res!=1) return 1;    else return 0;} bool Miller_Rabin(ll n) {    if (n<2) return 0;    if (n==2) return 1;    if (!(n&1)) return 0;    ll x=n-1,t=0;    while (!(x&1)) x>>=1,t++;    fo(i,1,S) {        ll a=rand()%(n-1)+1;        if (check(a,n,x,t)) return 0;    }    return 1;}ll Pollard_rho(ll n,ll t) {    int i=1,k=2;    ll x0=rand()%n,y=x0;    while (1) {        i++;        x0=(mult(x0,x0,n)+t)%n;        ll d=gcd(y-x0,n);        if(d!=1&&d!=n) return d;          if(y==x0) return n;          if(i==k) y=x0,k<<=1;          tmp++;    }  }void find(ll n) {    if (n==1) return;    if (Miller_Rabin(n)) {        pri[++tot]=n;        return;    }    ll p=n;tmp=0;    while (p>=n) p=Pollard_rho(p,rand()%(n-1)+1);    printf("%d\n",tmp);    find(p);find(n/p);}void dfs(int x,ll y,ll phi) {    if (x>cnt) {        (ans+=gcd(y,m)%Mo*pwr(m,n/y,Mo)%Mo*phi%Mo)%=Mo;        return;    }    ll z=1,p=1;    fo(i,0,b[x]) {        dfs(x+1,y*z,phi*p%Mo);        z=z*a[x];        if (i==0) p=p*(a[x]-1)%Mo;        else p=p*a[x]%Mo;    }}int ty;int main() {    freopen("necklace.in","r",stdin);    freopen("necklace.out","w",stdout);    ll inv2=pwr(2,Mo-2,Mo);srand(233333);    for(scanf("%d",&ty);ty;ty--) {        scanf("%lld%lld",&n,&m);        nn=n%Mo;mm=m%Mo;        if (n&1) ans=pwr(m,n/2+1,Mo)*nn%Mo;        else {            if (m&1) ans=pwr(m,n/2,Mo)*nn%Mo*inv2%Mo;            else ans=pwr(m,n/2,Mo)*nn%Mo;            (ans+=pwr(m,n/2+1,Mo)*nn%Mo*inv2%Mo)%=Mo;        }        tot=cnt=0;find(n);        sort(pri+1,pri+tot+1);        fo(i,1,tot)             if (pri[i]!=pri[i-1]) a[++cnt]=pri[i],b[cnt]=1;            else b[cnt]++;        dfs(1,1,1);        ans=ans*pwr(nn*mm*2%Mo,Mo-2,Mo)%Mo;        printf("%d\n",ans);    }}
原创粉丝点击