【luogu 2529】【SHOI 2001】击鼓传花
【原题题面】传送门
【题解大意】
这篇题解写得太清晰易懂了,我就不赘述了。
讲讲在上面那篇博客中没有直接写出来但是可能影响理解的东西:
f(x) = f(x/5) × a(x % 20)
已知非零的最后一位一定是偶数之后,我们考虑把每20个数分成一组,这样他们相乘4*4%10==6
对后面分不成一块的数的乘积(无论为多少,都毫不影响。
算法的实现:
我们给出的数记作x,起答案为ans[x]。
1.高精%单精(20) = y;
2.答案记作为ans[x] = a[y]*ans[x/5];
ans[x] = a[y]*ans[x/5] = a[y1]*a[y2]*ans[x/5/5] = ...
直到 x<20.
关于a数组的预处理应该为:
1,2,3,4,1/2,5,6,7,8,9,1/2,11,12,13,14,1/2,16,17,18,19,1/2的前缀乘并且时刻记住%10。
每20个数分组,所以分不到组内的数的个数小于20.即我们需要预处理的数的个数小于20。
【code】
#include<bits/stdc++.h> using namespace std; #define File "" #define ll long long inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } const int mxn = 110; char s[mxn]; int T,a[mxn],b[22],n; inline int calc1(){ return (a[2]*10+a[1]) % 20; } inline void calc2(){ int t = 0; for(int i = n;i >= 1; --i){ t = t*10+a[i]; a[i] = t/5; t = t%5; } } int ans; int main(){ // file(); T = 5,b[0] = 1; for(int i = 1;i <= 20; ++i){ if(!(i%5)) b[i] = b[i-1]/2%10; else b[i] = b[i-1]*i%10; } // for(int i = 1;i <= 20; ++i) printf("%d ",b[i]); // puts(""); while(T--){ scanf("%s",s+1); n = strlen(s+1); for(int i = 1;i <= n; ++i) a[n-i+1] = s[i]-'0'; ans = 1; while(n > 0){ while(a[n]==0) n--; ans = ans*b[calc1()]%10; calc2(); } printf("%d\n",ans); } return 0; } /* 11 12 13 14 15 */
G102的孤儿们都要好好的啊。