HUST 1569(Burnside定理+容斥+数位dp+矩阵快速幂)

 

传送门:Gift

题意:由n(n<=1e9)个珍珠构成的项链,珍珠包含幸运数字(有且仅由4或7组成),取区间[L,R]内的数字,相邻的数字不能相同,且旋转得到的相同的数列为一种,为最终能构成多少种项链。

分析:这是我做过的最为综合的一道题目(太渣了),首先数位dp筛选出区间[L,R]内的幸运数字总数,dp[pos]表示非限制条件下还有pos位含有的幸运数字个数,然后记忆化搜索一下,随便乱搞的(直接dfs不知会不会超时,本人做法900+ms险过,应该直接dfs会超时),再不考虑旋转相同的情况,可以dp再构造矩阵,dp[i][0]表示到达第i位时,最后一个珠子与第一个珠子不同,dp[i][1]表示到达第i位最后一个珠子与第一个相同,则状态转移方程为:

dp[i][0]=dp[i-1][0]*(m-2)+dp[i-1][1]*(m-1)(m为幸运数字种类).

dp[i][1]=dp[i-1][0]*1

上面构造矩阵快速幂求出总数后再由Burnside定理+容斥得到答案,这个问题较为常见,可参考poj2888做法。

#include <stdio.h>

#include <cstring>

#include <cmath>

#include <algorithm>

#include <queue>

#include <cstdlib>

#define LL long long

#define N 25

#define mod 1000000007

using namespace std;

/**************************矩阵快速幂**************************/

struct matrix

{

    LL m[2][2];

    void init()

    {

        for(int i=0;i<2;i++)

            for(int j=0;j<2;j++)

            m[i][j]=(i==j);

    }

}M;

matrix mult(matrix a,matrix b)

{

    matrix c;

    memset(c.m,0,sizeof(c.m));

    for(int k=0;k<2;k++)

    for(int i=0;i<2;i++)

    {

        if(a.m[i][k]==0)continue;

        for(int j=0;j<2;j++)

        {

            c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;

        }

    }



    return c;

}

matrix quick_pow(matrix a,int n)

{

    matrix res;

    res.init();

    while(n)

    {

        if(n&1)res=mult(res,a);

        a=mult(a,a);

        n>>=1;

    }

    return res;

}

LL calc(LL n,LL m)

{

    matrix res;

    res.m[0][0]=m-2;res.m[0][1]=m-1;

    res.m[1][0]=1;res.m[1][1]=0;

    res=quick_pow(res,n-1);

  //  printf("m=%lld n=%lld res=%lld\n",m,n,res.m[0][1]);

    return m*res.m[0][1]%mod;

}

/**************************矩阵快速幂**************************/

LL POW(LL a,LL n)

{

    LL res=1;

    a%=mod;

    while(n)

    {

        if(n&1)res=res*a%mod;

        a=a*a%mod;

        n>>=1;

    }

    return res;

}

/**********************容斥**************************/

#define MAXN 12

#define MAXM 32000

#define EPS 1e-8

bool p[MAXM];

vector<int> prime;

vector<int> factor;

vector<int> primefactor;

void Init() {

    int i, j;

    prime.clear();

    memset(p, true, sizeof(p));

    for (i = 2; i < 180; i++) {

        if (p[i]) {

            for (j = i * i; j < MAXM; j += i)

                p[j] = false;

        }

    }

    for (i = 2; i < MAXM; i++) {

        if (p[i])

            prime.push_back(i);

    }

}

void Prime(int x) {

    int i, tmp;

    primefactor.clear();

    tmp = (int) (sqrt((double) x) + EPS);

    for (i = 0; prime[i] <= tmp; i++) {

        if (x % prime[i] == 0) {

            primefactor.push_back(prime[i]);

            while (x % prime[i] == 0)

                x /= prime[i];

        }

    }

    if (x > 1)

        primefactor.push_back(x);

}

int Mul(int x, int &k) {

    int i, ans;

    ans = 1;

    for (i = k = 0; x; x >>= 1, i++) {

        if (x & 1) {

            k++;

            ans *= primefactor[i];

        }

    }

    return ans;

}

LL Phi(int x) {

    int i, j, t, ans, tmp;

    Prime(x);

    ans = 0;

    t = (int) primefactor.size();

    for (i = 1; i < (1 << t); i++) {

        tmp = Mul(i, j);

        if (j & 1)

            ans += x / tmp;

        else

            ans -= x / tmp;

    }

    return (x - ans) %mod;

}

/**********************容斥**************************/

LL solve(LL n,LL m)

{

    LL ans=0;

    for(int i=1;i*i<=n;i++)

    {

        if(n%i==0)

        {

            int a=i,b=n/i;

            if(i*i==n)

            {

                ans=(ans+Phi(n/a)*calc(a,m))%mod;

            }

            else

            {

                ans=(ans+Phi(n/a)*calc(a,m))%mod;

                ans=(ans+Phi(n/b)*calc(b,m))%mod;

            }

        }

    }

    ans=ans*POW(n,mod-2)%mod;

    return ans;

}

/************************数位dp**********************/

LL dig[25],dp[25];

LL dfs(int pos,int flag,int limit,int fzore)

{

    if(pos==0)return flag;

    if(!fzore&&!limit&&~dp[pos])return dp[pos];

    int len=limit?dig[pos]:9;

    LL ans=0;

    for(int i=0;i<=len;i++)

    {

        if(i==4||i==7||i==0){

        if(fzore&&i==0)ans+=dfs(pos-1,0,i==len&&limit,1);

        else if(i==4||i==7)ans+=dfs(pos-1,1,i==len&&limit,0);}

    }

    if(!fzore&&!limit)dp[pos]=ans;

    return ans;

}

LL fun(LL x)

{

    int len=0;

    if(x<4)return 0;

    while(x)

    {

        dig[++len]=x%10;

        x/=10;

    }

    return dfs(len,0,1,1);

}

/************************数位dp**********************/

int main()

{

    LL n,L,R;

    Init();

    memset(dp,-1,sizeof(dp));

    while(scanf("%lld%lld%lld",&n,&L,&R)>0)

    {

        LL num=fun(R)-fun(L-1);

        if(n==0)

        {

            puts("0");continue;

        }

        if(n==1)

        {

            printf("%d\n",num%mod);

            continue;

        }

        printf("%d\n",solve(n,num));



    }

}
View Code

 

你可能感兴趣的:(ide)