zoukankan      html  css  js  c++  java
  • bzoj2757【scoi2012】Blinker的仰慕者

    题目描述

    Blinker 有非常多的仰慕者,他给每个仰慕者一个正整数编号。而且这些编号还隐藏着特殊的意义,即编号的各位数字之积表示这名仰慕者对Blinker的重要度。 现在Blinker想知道编号介于某两个值A,B之间,且重要度为某个定值K的仰慕者编号和。 


    输入格式

    输入的第一行是一个整数N,表示Blinker想知道的信息个数。 
    接下来的N行,每行有三个数,A,B,K。表示 Blinker想知道编号介于A和B之间的,
    重要度为K的仰慕者的编号和。           


    输出格式


    输出N行,每行输出介于A和B之间,重要度为 K的仰慕者编号和。结果可能很大,
    模上20120427。 


    提示

    【数据范围】 
    对于20%的数据,保证:  2<=A<=B<=1000000000,1<=N<=30 
    对于50%的数据,保证:2<=A<=B<=1000000000000000000,1<=N<=30 
    对于100%的数据,保证:  2<=A<=B<=1000000000000000000,1<=N<=5000


     

    • 题解:

      • 由于因子只有2 3 5 7 , 状态大概有3e4+,不超过4e4;
      • 用HASH_TABLE存下来;
      • 多组询问,先预处理$i$位的答案;
      • 对每组询问$dfs$统计答案,如果没有前导零并且没有抵达上界则直接返回,否则进一步$dfs$
      • 代码不太好些,注释里有关于变量的说明;
      • 注意$K=0$和$K eq 0$最好分开统计;
      • $n$为位数上界,时间复杂度:$O(T*10n +n*4e4*10)$
     1 #include<bits/stdc++.h>
     2 #define ll long long 
     3 using namespace std;
     4 const int N=20,M=4e4,sz=1234561,mod=20120427;
     5 ll A,B,K;
     6 int cnt,a[N],pw[N];
     7 int o,hd[sz],nt[sz];ll v[sz];
     8 void upd(int&x,int y){x+=y;if(x>=mod)x-=mod;}
     9 void add(ll x){
    10     int u=x%sz;
    11     for(int i=hd[u];i;i=nt[i])if(v[i]==x)return;
    12     nt[++o]=hd[u],hd[u]=o,v[o]=x;
    13 } 
    14 int find(ll x){
    15     int u=x%sz;
    16     for(int i=hd[u];i;i=nt[i])if(v[i]==x)return i;
    17     return 0;
    18 }//HASH表 
    19 void dfs(int x,int y,ll z){
    20     if(x==18)add(z);
    21     else{
    22         if(!y)return;
    23         for(int i=x;i<=18;++i){
    24             dfs(i,y-1,z);
    25             z*=y;
    26         }
    27     }
    28 }//dfs方案 
    29 namespace Solve{
    30     int f[N][M],g[N][M];//f[位数][乘积] 
    31     void init(){
    32         f[0][1]=1;
    33         for(int i=0;i<18;++i)
    34         for(int j=1;j<=o;++j)
    35         if(f[i][j]){
    36             for(int l=0;l<=9;++l){
    37                 int y=find(v[j]*l);
    38                 upd(f[i+1][y],f[i][j]);
    39                 upd(g[i+1][y],(g[i][j]*10+f[i][j]*l)%mod);
    40             }
    41         }
    42     }//预处理i位无限制的答案 
    43     int cal1(int i,int j,int k,ll x,ll y){//已经枚举好的位数,前导零,上界,前i位的值,当前K 
    44         if(i==cnt)return y==1?x:0; 
    45         if(!k&&!j)return (1ll*x*pw[cnt-i]%mod*f[cnt-i][find(y)]%mod+g[cnt-i][find(y)])%mod; 
    46         int re=0,l=j?0:1,r=k?a[i+1]:9;
    47         for(int i1=l,t;i1<=r;++i1)if(!i1||y%i1==0){
    48             ll y1=!i1?y:y/i1;
    49             upd(re, t=cal1(i+1,j&&!i1,k&&i1==a[i+1],(x*10+i1)%mod,y1));
    50         }
    51         return re;
    52     }
    53     int cal0(int i,int j,int k,ll x,ll y){//前四个同cal1,y为前i为是否出现0 
    54         if(i==cnt)return !y?x:0;
    55         if(!k&&!j){
    56             if(!y)return (1ll*x*pw[cnt-i]%mod*pw[cnt-i]%mod+1ll*(pw[cnt-i]-1)*pw[cnt-i]/2%mod)%mod;//后面cnt-i任意; 
    57             else return 1ll*x*pw[cnt-i]%mod*f[cnt-i][o]%mod+g[cnt-i][o];//后面cnt-i为乘积为0; 
    58         }
    59         int re=0,l=0,r=k?a[i+1]:9;
    60         for(int i1=l;i1<=r;++i1){
    61             int y1=j&&!i1?1:y*i1;
    62             upd(re, cal0(i+1,j&&!i1,k&&i1==a[i+1],(x*10+i1)%mod,y1));
    63         }
    64         return re;
    65     } 
    66     //注意理解一下两个方面:
    67     //是如何统计前i位达到上界,i+1位不是上界的答案的;(状态k)
    68     //是如何统计位数小于上界位数cnt的答案的; (状态j)
    69     //上界是如何被统计的(line44)  
    70 }
    71 int main(){
    72     #ifndef ONLINE_JUDGE
    73     freopen("T2.in","r",stdin);
    74     freopen("T2.out","w",stdout);
    75     #endif
    76     dfs(0,9,1);add(0);
    77     Solve::init();
    78     for(int i=pw[0]=1;i<=18;++i)pw[i]=pw[i-1]*10%mod;
    79     int T;scanf("%d",&T);
    80     while(T--){
    81         int ans=0;
    82         scanf("%lld%lld%lld",&A,&B,&K);A--;
    83         cnt=0;while(A)a[++cnt]=A%10,A/=10;
    84         for(int i=1;i<=cnt>>1;++i)swap(a[i],a[cnt-i+1]);
    85         ans-= K?Solve::cal1(0,1,1,0,K) : Solve::cal0(0,1,1,0,1);
    86         cnt=0;while(B)a[++cnt]=B%10,B/=10;
    87         for(int i=1;i<=cnt>>1;++i)swap(a[i],a[cnt-i+1]);
    88         ans+= K?Solve::cal1(0,1,1,0,K) : Solve::cal0(0,1,1,0,1);
    89         printf("%d
    ",(ans%mod+mod)%mod);
    90     }
    91     return 0;
    92 }
    View Code
  • 相关阅读:
    131. Palindrome Partitioning
    130. Surrounded Regions
    129. Sum Root to Leaf Numbers
    128. Longest Consecutive Sequence
    125. Valid Palindrome
    124. Binary Tree Maximum Path Sum
    122. Best Time to Buy and Sell Stock II
    121. Best Time to Buy and Sell Stock
    120. Triangle
    119. Pascal's Triangle II
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10410499.html
Copyright © 2011-2022 走看看