bzoj4330 JSOI2012 爱之项链

题目链接:bzoj4330
题目大意:
一枚戒指由M个带磁性的特殊彩色球状物连接而成。所有带磁性的特殊彩色球状物的颜色只有R种,这里我们用1到R来表示。如果一枚戒指可以通过顺时针或逆时针的旋转后与另外一枚戒指相同,则认为这是两枚相同的戒指。
对于一条爱之项链,由N个戒指和一个特殊纪念品连接成。要求满足任何相邻两枚戒指必须是不相同的。同时,特殊纪念品左右两枚戒指也必须是不同的。
现在给定N,M和R,问究竟有多少种不同的爱之项链。
注意:
1、特殊纪念品的插入位置不同,也许会得到不同的爱之项链。
2、这里我们只考虑旋转后是否相同,不考虑翻转操作,这一点不论是对于每一枚戒指,还是对于整条项链,都是这样的。

题解:
置换+矩乘
虽然一眼置换,但是然后就跳题了orz

根据不知道算是burnside还是ploya可以知道,不同种类的个数为不动点的个数除以置换总数。当把一个置换里的每个循环节都分别染上相同的颜色时,就是一个不动点。
va 为不同戒指的种数。
va=Rc(gi)M ,c(gi)表示gi这种置换的循环节的个数。
因为戒指是看旋转的,枚举旋转一下移 i 位,那么有 循环节的个数为 gcd(i,M)
证明:
c 为循环节的长度。因为要封闭,所以最后会回到起始点即走过了 kM 位。
即有 i×d=k×M
满足条件的最小的 kM 就是 lcm(i,M)
所以就是 i×d=lcm(i,M) ,即 d=lcm(i,M)i=M×gcd(i,M)
因为对称性(?),每个循环节的长度都是一样的。
所以就有循环节的个数 =M×gcd(i,M)M=gcd(i,M)
于是 va=Mi=1Rgcd(i,M)M
但是M≤ 109 ,不能直接做。我们来看 Mi=1Rgcd(i,M)
Mi=1Rgcd(i,M)=d|MRdmdi=1[gcd(i,md)=1]=d|MRdφ(md)
M≤ 109 φ 直接算,M也直接 M 枚举约数就好了。

然后到了项链那一帕。
我们以特殊装饰物的一边为首一边为尾拉成一条链。
设f[i][0]表示串了i个戒指首尾不同的方案数,f[i][1]表示串了i个戒指首尾不一定不同(即随便串的)的方案数。但都一定满足相邻的不同。
于是有
f [ i ][ 1 ] =f [ i - 1 ][ 1 ] × (va-1)
f [ i ][ 0 ]=f[ i - 1 ][ 0 ] × (va-2)+(f [ i - 1 ][ 1 ]-f [ i - 1 ][ 0 ]) × (va-1)
=f[ i - 1 ][ 1 ] × (va-1)-f[ i - 1 ][ 0 ]
其中的f [ i - 1 ][ 1 ] - f [ i - 1 ][ 0 ]表示的是串了i-1个首尾相同的方案数。
这个可以用矩阵加速,定义一个这样的矩阵
————-
| -1 | va-1|
————-
| 0 | va-1|
————-
就可以求得 f[N][0]

#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
#define maxn 101000

int qm;LL mod=3214567LL;
LL mymin(LL x,LL y){return (x1;
    while (t)
    {
        if (t&1) ret=(ret*x)%mod;
        x=(x*x)%mod;t>>=1;
    }
    return ret;
}
LL phi(int x)
{
    if (x==1) return 1LL;
    LL ans=(LL)x;
    for (int i=2;i*i<=x;i++)
     if (x%i==0)
     {
         ans*=(i-1)*qpow(i,mod-2)%mod;
         ans%=mod;
         while (x%i==0) x/=i;
     }
    if (x!=1) ans=ans*(x-1)%mod*qpow(x,mod-2)%mod;
    return ans;
}
struct mrix {LL a[2][2];LL l,r;mrix(){memset(a,0,sizeof(a));}};
mrix mmult(mrix x,mrix y)
{
    mrix ret;
    ret.l=x.l;ret.r=y.r;
    for (int i=0;ifor (int j=0;jfor (int k=0;kmod;
          ret.a[i][j]%=mod;
      }       
    return ret;
}
mrix powm(mrix x,LL t)
{
    mrix ret;ret.l=ret.r=2;
    ret.a[0][0]=ret.a[1][1]=1;
    while (t)
    {
        if (t&1) ret=mmult(ret,x);
        x=mmult(x,x);t>>=1;
    }
    return ret;
}
int main()
{
    //freopen("love.in","r",stdin);
    //freopen("love.out","w",stdout);
    LL n,r,va=0;int m,i;
    scanf("%lld%d%lld",&n,&m,&r);
    if (m%mod==0) mod*=mod;
    qm=(int)sqrt(m);//pre();
    for (i=1;i*i<=m;i++)
     if (m%i==0)
     {
        va+=qpow(r,(LL)m/i)*phi(i)%mod;
        if (i*i==m) break;
        va+=qpow(r,(LL)i)*phi(m/i)%mod;
        va%=mod;
     }
    va=va*qpow(m,mod-2)%mod;

    mrix dw;dw.l=dw.r=2;
    dw.a[0][0]=-1;dw.a[1][0]=0;
    dw.a[0][1]=dw.a[1][1]=va-1;

    dw=powm(dw,n-1);

    LL ans=dw.a[0][1]*va%mod;
    if (ans<0) ans+=mod;
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(矩阵乘法,置换,置换,矩阵乘法)