• 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
    ",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
    ",num%mod);
                continue;
            }
            printf("%d
    ",solve(n,num));
    
        }
    }
    View Code
  • 相关阅读:
    阿里云CentOS 7无外网IP的ECS访问外网(配置网关服务器)
    CentOS 7配置成网关服务器
    Mac/Ubuntu下的数据建模工具PDMan,替代PowerDesigner
    Docker卸载高版本重装低版本后启动提示:driver not supported
    Redis连接出现Error: Connection reset by peer的问题是由于使用Redis的安全模式
    Mac流量监控/硬盘监控小工具
    CentOS 7创建自定义KVM模板(现有KVM迁移到另外一台机)
    vi显示行号
    阿里云与微软云的对照表
    CentOS下安装Jenkins(Docker/war/tomcat/java -jar)
  • 原文地址:https://www.cnblogs.com/lienus/p/4395196.html
Copyright © 2020-2023  润新知