hdu_5085_Counting problem(莫队分块思想)

题目连接:hdu_5085_Counting problem

题意:给你一个计算公式,然后给你一个区间,问这个区间内满足条件的数有多少个

题解:由于这个公式比较特殊,具有可加性,我们考虑讲一个数分为两个部分,这样就可以用莫队的思想均摊时间复杂度,将9位数分为一个4位和一个5位,这里我感觉sqr为10000 速度比较快。然后如果b小于sqr,那么直接暴力就行,如果b大于sqr,那么我们要把a和b都分为头部和尾部(注意是闭区间,a需要减1),如果a小于sqr,那么他的头部就为0,然后计算0-a的尾部,并将相应的值插入Hash表,然后计算以a头部开头满足条件的数,记为reta,同理,计算0-b的尾部,记为retb,如果b尾小于a尾,就要先计算b再计算a,然后将0到sqr-1的数对应的值也全部插入Hash表,然后从a的头到b的头,寻找对应的值,这里要用一下容斥定理,retb-reta就是从[a,b]之间满条件的数的个数.


 1 #include<cstdio>
 2 #define F(i,a,b) for(int i=a;i<=b;i++)
 3 typedef long long LL;
 4 
 5 const LL M=(1<<20)-1,N=1e5+7,sqr=1e4;
 6 LL K,a,b,ahd,bhd,bt,at,reta,retb,T,S,dt[10][16];
 7 inline LL pow(LL x,LL k){
 8     LL an=1;
 9     while(k){
10         if(k&1)an*=x;
11         k>>=1,x*=x;
12     }
13     return an;
14 }
15 //------------Hash table------------------------
16 struct E{LL key;LL cnt;E *nxt;}*g[M+1],pool[N],*cur=pool,*p;LL vis[M+1];
17 void init_Hash(){T++,cur=pool;}
18 inline void ins(LL key){
19     if(key>S)return;
20     LL u=key&M;
21     if(vis[u]<T)vis[u]=T,g[u]=NULL;
22     for(p=g[u];p;p=p->nxt)if(p->key==key){p->cnt++;return;}
23     p=cur++,p->key=key,p->cnt=1,p->nxt=g[u],g[u]=p;
24 }
25 
26 inline LL ask(LL key){
27     if(key<0)return 0;
28     LL u=key&M;
29     if(vis[u]<T)return 0;
30     for(p=g[u];p;p=p->nxt)if(p->key==key)return p->cnt;
31     return 0;
32 }
33 //----------------------------------------------
34 inline LL cal(LL x){
35     LL an=0;
36     while(x)an+=dt[x%10][K],x/=10;
37     return an;
38 }
39 void init(){F(i,0,9)F(j,1,15)dt[i][j]=pow(i,j);}
40 int main(){
41     init();
42     while(~scanf("%lld%lld%lld%lld",&a,&b,&K,&S)){
43         init_Hash();
44         ahd=(a-1)/sqr,bhd=b/sqr,at=(a-1)%sqr,bt=b%sqr;
45         if(at<bt){
46         F(i,0,at)ins(cal(i));
47         reta=ask(S-cal(ahd));
48         F(i,at+1,bt)ins(cal(i));
49         retb=ask(S-cal(bhd));
50         F(i,bt+1,sqr-1)ins(cal(i));
51     }else{
52         F(i,0,bt)ins(cal(i));
53         retb=ask(S-cal(bhd));
54         F(i,bt+1,at)ins(cal(i));
55         reta=ask(S-cal(ahd));
56         F(i,at+1,sqr-1)ins(cal(i));
57     }
58     F(i,ahd,bhd-1)retb+=ask(S-cal(i));
59     printf("%lld\n",retb-reta);
60     }
61     return 0;
62 }
View Code

 



 

转载于:https://www.cnblogs.com/bin-gege/p/5696092.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值