【GDOI2016模拟4.22】数字方阵
2016-04-28 20:45
357 查看
Description
Anica 做了一个很奇怪的梦:她梦见了一个无限大的平板,平板上填着无限行和无限列的整数。有趣的是,每个整数在那神奇的平板上只出现有限的次数。机智的Anica很快便发现了这其中数字的规律,每一行第一列的数字表示当前的行号,其它非第一列的数字,为该位置左边一列的数字加上其数字的翻转数字之和。为了方便描述,我们定义A[i,j]表示平板上第i行第j列的数字:
1. A[i,1] = i,
2. A[i,j] = A[i,j-1] + Rev( A[i,j-1] ), 其中Rev(x)表示x在10进制下的翻转,例如Rev(213) = 312, Rev(406800) = 008604 = 8604 。
然而,Anica对这堆数字不太感兴趣。她看了一下平板的背面,并发现了一盏神灯,同时神灯也发现了Anica,这时一个精灵冒了出来:
精灵:“Anica,如果你能答对我Q个问题,你将获得一份神秘的礼物,否则你将无法无法醒来,哈哈哈哈~~”
精灵:“每个问题将给你两个整数A和B,请问区间[A,B]的数字总共在平板上出现了多少次?”
Anica:“我不想要你的礼物,我只想要醒过来,我还有很多事情要做呢!”
Input
第一行给出一个整数Q (1 <= Q <=10^5),表示问题的数量。接下来Q行,每行两个整数A,B (1 <= A,B <= 10^10),表示每个询问的区间[A,B]。
Output
输出Q行,第i行一个整数,表示第i个询问的答案。Sample Input
样例输入1:2
1 10
5 8
样例输入2:
3
17 144
121 121
89 98
样例输入3:
1
1 1000000000
Sample Output
样例输出1:18
8
样例输出2:
265
25
10
样例输出3:
1863025563
Data Constraint
50%的分数保证1 <= A,B <= 10^6。Solution
对于50%:发现数据比较小,暴力。直接暴力第一列的数,每次f[x+rev(x)]+=f[x]。对f求前缀和,每次询问就是f[r]-f[l-1]。比较简单。对于100%:
同样是暴力,但是要特别一点。
可以发现,总共的数的数量不会超过195,等会证明。那么,如何暴力这些数呢?
如果
x长为L=a1 a2 a3.. aL
rev(x)=aL aL-1 .. a1
x+rev(x)=a1+aL a2+aL-1 a3+aL-2 aL+a1
得到一个对称的数。L最大为10,那么一半就是5。分别为0~18中一个共19个,所以大约有195个数。
爆搜这些数,算出它在第二列时有多少种可能从第一列转移过来,存到f里面。接着同50分一样,最后二分一下就行了。
注意:存数用hash,表开大一点。最好所有数组与变量开longlong。
code
#include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <iostream> #define fo(i,a,b) for(ll i=a;i<=b;i++) #define ll long long #define mo 6412345 using namespace std; struct note { ll x,y; }; note a[mo]; ll b[6],hsh[mo+5],has[mo+5],len,k=0,c[19],tot=0; ll rev(ll x) { ll jy=0; for(;x;x/=10) jy=jy*10+x%10; return jy; } ll hash(ll x) { ll y; y=x%mo+1; while (hsh[y]!=0 && hsh[y]!=x) y=(y+1)%mo; return y; } void dg(int j) { if (j>len) { ll x=1,y=0; fo(i,1,len) { ll jy=c[b[i]]; if (i==1 && b[i]<10) jy--; if (i==len && k%2==1) { if(b[i]%2==1) jy=0; else jy=1; } x*=jy; if (i!=len) y=y*10+b[i]; } if (x==0) return; if (k%2==0) y=y*10+b[len]; for(int i=len;i>=1;i--) y=y*10+b[i]; ll jy=hash(y); if (hsh[jy]==0) a[++tot].x=y,a[tot].y=x,hsh[jy]=y,has[jy]=tot; else a[has[jy]].y+=x; return; } ll kk;kk=j==1?1:0; fo(i,kk,18) { b[j]=i;dg(j+1); } } bool cmp(note x,note y){return x.x<y.x;} ll find(ll l,ll r,ll k) { ll mid; for(;l+1<r;) { mid=(l+r)/2; if (a[mid].x<=k) l=mid;else r=mid; } if (a[r].x<=k) l=r;return l; } int main() { freopen("table.in","r",stdin);freopen("table.out","w",stdout); fo(i,0,9) fo(j,0,9) c[i+j]++; for(len=1;len<=5;len++) { k++;dg(1);k++;dg(1); } sort(a+1,a+1+tot,cmp); fo(i,1,tot) { ll x=a[i].x;x=x+rev(x); if (x<=a[tot].x) a[find(0,tot,x)].y+=a[i].y; } fo(i,1,tot) a[i].y+=a[i-1].y; int ak;scanf("%d",&ak); while (ak-->0) { ll l,r;scanf("%lld%lld",&l,&r); ll x=find(0,tot,r);ll y=find(0,tot,l); if (a[y].x==l) y--; printf("%lld\n",a[x].y-a[y].y+r-l+1); } fclose(stdin);fclose(stdout); }
相关文章推荐
- log4j.properties
- java并发编程(2)--Thread类的使用
- Unity3d碰撞检测中碰撞器与触发器的区别
- uscao母亲的牛奶 dfs
- nyoj 1236挑战密室 河南省第八届大学生程序设计大赛acm
- hdu5249
- 团队项目2.0
- 插入U盘时Win7总提示扫描并修复U盘的解决办法
- HDU1728-逃离迷宫
- linux中安装常用软件
- 分享5个可视化的正则表达式编辑工具
- 设计模式二三事——桥接模式
- 多线程的三种实现方法{转载}
- java设计模式-抽象工厂模式
- 微信支付 生成付款二维码链接 并生成支付二维码图片 .net C#
- SqlServer 2008 R2 域环境镜像问题小结
- 《构建之法》第6~7章读后感
- 对windows消息机制的理解
- IDEA新建MAVEN项目时速度缓慢
- 集合类