• 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
  • 相关阅读:
    SpringBoot使用token简单鉴权
    SpringBoot-dubbo自定义负载均衡实现简单灰度
    SpringBoot基于数据库实现简单的分布式锁
    使用canal增量同步mysql数据库信息到ElasticSearch
    使用go-mysql-elasticsearch同步mysql数据库信息到ElasticSearch
    使用logstash同步mysql数据库信息到ElasticSearch
    extract()函数:用于从一个date或者interval类型中截取到特定的部分
    转://IO的基础概念
    转://MySQL客户端工具的选择
    转://oracle 软件的收费模式
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10410499.html
Copyright © 2020-2023  润新知