• bzoj千题计划268:bzoj3131: [Sdoi2013]淘金


    http://www.lydsy.com/JudgeOnline/problem.php?id=3131

    如果已知 s[i]=j 表示有j个<=n数的数码乘积=i

    那么就会有 s[a1]*s[a2] 个数 在一阵风之后到(a1,a2)位置

    把所有的j用一个数组b存起来,从大到小排序
    开始把(1,1)存入堆,表示当前最多的是b[1]*b[1]
    每次取出堆顶(i,j),累加 b[i]*b[j],存入(i+1,j),(i,j+1),map 判重

    就可以解决前k大之和的问题

    i的上限是n,存不下,怎么办

    我们发现 n以内 有大量的i 是无用的

    只有质因数分解之后 质因子为2、3、5、7 的i 才是合法状态

    所以 dp[len][0/1][c2][c3][c5][c7] 表示前len位,是否卡上界,当前i=2^c2 * 3^c3 * 5^c5 * 7^c7 的 j是多少

    数位dp

    注意不能放0,但是可以有前导0,所以除了最高位,都要加上前导0的贡献,即dp[][0][0][0][0][0]++ (前导0不卡上界)

    #include<map>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    typedef long long LL;
    
    const int mod=1e9+7;
    
    LL dp[2][2][41][27][19][16];
    int f[10][4];
    
    int a[14];
    
    int cnt;
    LL b[10001];
    
    priority_queue< pair<LL,pair<int,int> > >q;
    map<pair<int,int>,bool>vis;
    
    void pre()
    {
        f[2][0]=1;
        f[3][1]=1;
        f[4][0]=2;
        f[5][2]=1;
        f[6][0]=1;
        f[6][1]=1;
        f[7][3]=1;
        f[8][0]=3;
        f[9][1]=2;
    }
    
    void reverse(int len)
    {
        int k=len/2;
        for(int i=1;i<=k;++i) swap(a[i],a[len-i+1]);
    }
    
    void ADD(int &x,int y)
    {
        x+=y;
        x-=x>=mod ? mod : 0;
    }
    
    LL Pow(LL a,int b)
    {
        LL res=1;
        for(;b;a*=a,b>>=1)
            if(b&1) res*=a;
        return res;
    }
    
    void numberDP(LL n)
    {
        int len=0;
        LL m=n;
        while(m) a[++len]=m%10,m/=10;
        reverse(len);
        int up,J;
        int now=0,nxt=1;
        for(int i=0;i<len;++i,swap(now,nxt))
        {
            if(!i) dp[now][1][0][0][0][0]++;
            else dp[now][0][0][0][0][0]++;
            memset(dp[nxt],0,sizeof(dp[nxt]));
            for(int j=0;j<=1;++j)
                for(int c2=0;c2<=40;++c2)
                    for(int c3=0;c3<=26;++c3)
                        for(int c5=0;c5<=18;++c5)
                            for(int c7=0;c7<=15;++c7)
                                if(dp[now][j][c2][c3][c5][c7])
                                {
                                    if(j) up=a[i+1];
                                    else up=9;
                                    for(int k=1;k<=up;++k)
                                    {
                                        J=(j && k==up);
                                        dp[nxt][J][c2+f[k][0]][c3+f[k][1]][c5+f[k][2]][c7+f[k][3]]+=dp[now][j][c2][c3][c5][c7];
                                    }
                                }
        }
        LL sum,tmp;
        for(int c2=0;c2<=40;++c2)
        {
            tmp=Pow(2,c2);
            if(tmp>n) break;
            for(int c3=0;c3<=26;++c3)
            {
                tmp=Pow(2,c2)*Pow(3,c3);
                if(tmp>n) break;
                for(int c5=0;c5<=18;++c5)
                {
                    tmp=Pow(2,c2)*Pow(3,c3)*Pow(5,c5);
                    if(tmp>n) break;
                    for(int c7=0;c7<=15;++c7)
                    {
                        tmp=Pow(2,c2)*Pow(3,c3)*Pow(5,c5)*Pow(7,c7);
                        if(tmp>n) break;
                        sum=dp[now][0][c2][c3][c5][c7]+dp[now][1][c2][c3][c5][c7];
                        if(sum) b[++cnt]=sum;/*,printf("%d %d %d %d %I64d
    ",c2,c3,c5,c7,sum)*/;
                    }
                }
            }
        }
    }
    
    void get_kth(int k)
    {
        sort(b+1,b+cnt+1,greater<int>());
        int i=1,j=1;
        int ans=0;
        pair<LL,pair<int,int> >pr;
        int x,y;
        q.push(make_pair(b[1]*b[1],make_pair(1,1)));
        while(k-- && !q.empty())
        {
            pr=q.top();
            q.pop();
            if(!pr.first) break;
            ADD(ans,pr.first%mod);
            x=pr.second.first;
            y=pr.second.second;
            if(!vis[make_pair(x+1,y)]) 
            {
                q.push(make_pair(b[x+1]*b[y],make_pair(x+1,y)));
                vis[make_pair(x+1,y)]=true;
            }
            if(!vis[make_pair(x,y+1)]) 
            {
                q.push(make_pair(b[x]*b[y+1],make_pair(x,y+1)));
                vis[make_pair(x,y+1)]=true;
            }
        }
        printf("%d",ans);
    }
    
    int main()
    {
        //freopen("gold.in","r",stdin);
        //freopen("gold.out","w",stdout);
        LL n; int k;
        scanf("%lld%d",&n,&k);
        pre();
        numberDP(n);
        get_kth(k);
        return 0;
    }
  • 相关阅读:
    nginx 附件上传不上去 client_max_body_size 设置的太小
    python 1
    NGINX 常用配置
    Linux OOM Killer 保护机制
    MacbookPro接上HDM连接显示器不能上网的解决方法
    python 逻辑运算符 () > not > and > or
    TASSL 服务端 客户端测试代码
    SSL通信双方如何判断对方采用了国密
    C/S boringSSL那点事
    从Chrome源码看浏览器的事件机制
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8536499.html
Copyright © 2020-2023  润新知