LA6575 Odd and Even Zeroes (2013-2014 ACM-ICPC Southwestern Europe Regional Contest F题) 规律
2014-10-09 16:48
495 查看
题意:给定一个数n,判定0! , 1! , 2!, ... , n!这(n+1)个阶乘有多少个末尾0的个数为偶数。 (0<=n<=10^18)
思路:i!末尾0个数取决于阶乘中5的个数。我们以5个数为一个整体。
1(5) 1(10) 1(15) 1(20) 2(25) 1(30) 1(35) 1(40) 1(45) 2(50) 1(55) 1(60) 1(65) 1(70) 2(75) 1(80) 1(85) 1(90) 1(95) 2(100) 1(105) 1(110)
1(115) 1(120) 3(125) 前一个数代表这个数中5的幂,后一个代表那个数。
我们将625以前的数分组如下:
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 4
那么哪些段是满足末尾0的个数为偶数呢? 我们将第一行的段表示出来,(y)为是,(n)为否
(y)1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 3
我们发现:
(1)已知直到出现第一个5的k次幂的大段,那么直到出现第一个5的(k+1)次幂的大段一定是5的k次幂的大段重复5段,且最后一段的最后
一个元素把k换成(k+1)即为直到出现第一个5的(k+1)次幂的大段。
(2)已知直到出现第一个5的k次幂的大段中每个小段的y/n情况,那么可以推知第一个5的(k+1)次幂的大段的每个小段的y/n情况。
1.如果k是偶数,那么接下来的4个段与之前的段情况完全相同。
2.如果k是奇数,那么接下来的4段中,第2和第4段与之前段的情况相同。第1和第3段与之前段的情况正好相反。
设num[ i ]表示分组后直到出现第一个5的i次幂时,之前满足末尾0的个数为偶数的段的个数。
那么
num[ i ]=5 * num[ i - 1] i为奇数;
num[ i ]=3 * num[ i - 1 ]+2 * ( a[ i - 2 ] - num[ i - 1 ] ) i为偶数;
预处理完num数组之后,对于n,我们每次二分找不大于n的最大次幂区间, 不妨设为k,x= n / a[ k ],那么n -= a[ k ] * x; 同时根据k的奇
偶性,更新ans。同时我们设了一个变量flag记录当前的翻转状态,flag=0表示剩余区间也是先从y开始的,即与num数组的状态一
致;flag=1表示剩余区间是从n开始的。每次更新完ans,同时根据k看是否需要翻转,详见代码:
思路:i!末尾0个数取决于阶乘中5的个数。我们以5个数为一个整体。
1(5) 1(10) 1(15) 1(20) 2(25) 1(30) 1(35) 1(40) 1(45) 2(50) 1(55) 1(60) 1(65) 1(70) 2(75) 1(80) 1(85) 1(90) 1(95) 2(100) 1(105) 1(110)
1(115) 1(120) 3(125) 前一个数代表这个数中5的幂,后一个代表那个数。
我们将625以前的数分组如下:
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 3
1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 2 1 1 1 1 4
那么哪些段是满足末尾0的个数为偶数呢? 我们将第一行的段表示出来,(y)为是,(n)为否
(y)1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 2 (y) 1 (n) 1 (y) 1 (n) 1 (y) 3
我们发现:
(1)已知直到出现第一个5的k次幂的大段,那么直到出现第一个5的(k+1)次幂的大段一定是5的k次幂的大段重复5段,且最后一段的最后
一个元素把k换成(k+1)即为直到出现第一个5的(k+1)次幂的大段。
(2)已知直到出现第一个5的k次幂的大段中每个小段的y/n情况,那么可以推知第一个5的(k+1)次幂的大段的每个小段的y/n情况。
1.如果k是偶数,那么接下来的4个段与之前的段情况完全相同。
2.如果k是奇数,那么接下来的4段中,第2和第4段与之前段的情况相同。第1和第3段与之前段的情况正好相反。
设num[ i ]表示分组后直到出现第一个5的i次幂时,之前满足末尾0的个数为偶数的段的个数。
那么
num[ i ]=5 * num[ i - 1] i为奇数;
num[ i ]=3 * num[ i - 1 ]+2 * ( a[ i - 2 ] - num[ i - 1 ] ) i为偶数;
预处理完num数组之后,对于n,我们每次二分找不大于n的最大次幂区间, 不妨设为k,x= n / a[ k ],那么n -= a[ k ] * x; 同时根据k的奇
偶性,更新ans。同时我们设了一个变量flag记录当前的翻转状态,flag=0表示剩余区间也是先从y开始的,即与num数组的状态一
致;flag=1表示剩余区间是从n开始的。每次更新完ans,同时根据k看是否需要翻转,详见代码:
// file name: LA6575.cpp // // author: kereo // // create time: 2014年10月08日 星期三 20时13分18秒 // //***********************************// #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #include<stack> #include<cmath> #include<string> #include<algorithm> using namespace std; typedef long long ll; const int MAXN=30; const int inf=0x3fffffff; const int mod=1000000000+7; #define L(x) (x<<1) #define R(x) (x<<1|1) ll n; ll num[MAXN]; ll a[MAXN]; int main() { num[1]=1; num[2]=3; a[0]=1; for(int i=1;i<MAXN;i++) a[i]=a[i-1]*5; for(int i=3;i<MAXN;i++){ if(i%2) num[i]=num[i-1]*5; else num[i]=3*num[i-1]+2*(a[i-2]-num[i-1]); } while(~scanf("%I64d",&n) && n!=-1){ ll ans=0; int flag=0; //flag=0表示1 0 1 0 1的形式,flag=1表示0 1 0 1 0的形式 if(n <= 4){ //特判下不能构成段的情况。 cout<<n+1<<endl; continue; } n++; while(n){ int k=upper_bound(a,a+MAXN,n)-a; k-=1; if(k == 0){ if(flag == 0) ans+=n; break; } ll x=n/a[k]; n-=a[k]*x; if(k&1){ if(x%2){ int a1=x/2,a2=(x+1)/2; if(!flag) ans+=a2*num[k]*5+a1*(a[k-1]-num[k])*5; else ans+=a1*num[k]*5+a2*(a[k-1]-num[k])*5; } else ans+=x/2*a[k-1]*5; } else{ if(flag == 0) ans+=num[k]*x*5; else ans+=(a[k-1]-num[k])*x*5; } if(k&1){ if(x%2) flag^=1; } } cout<<ans<<endl; } return 0; }
相关文章推荐
- LA6578 Trending Topic (2013-2014 ACM-ICPC Southwestern Europe Regional Contest I题) 模拟
- LA6576 VivoParc (2013-2014 ACM-ICPC Southwestern Europe Regional Contest G题) 搜索
- 2013-2014 ACM-ICPC, NEERC, Southern Subregional Contest Problem I. Plugs and Sockets 费用流
- The 2013 ACM-ICPC Asia Changsha Regional Contest J Josephina and RPG
- 2013-2014 ACM-ICPC, NEERC, Southern Subregional Contest Problem F. Judging Time Prediction 优先队列
- Problem C - Sums ACM/ICPC Central Europe Regional Contest 2014
- 2013-2014 ACM ICPC Central European Regional Contest (CERC 13) I题Crane
- 2013-2014 ACM ICPC Central European Regional Contest (CERC 13) B题What does the fox say?
- 2013-2014 ACM-ICPC, NEERC, Southern Subregional Contest Problem H. Password Service dp
- 2015-2016 ACM-ICPC Southwestern Europe Regional Contest (SWERC 15) C - Canvas Painting(优先队列)
- 2015-2016 ACM-ICPC Southwestern Europe Regional Contest (SWERC 15)训练总结【7/10】
- 2013-2014 ACM ICPC Central European Regional Contest (CERC 13) K题(dp)
- 2013-2014 ACM-ICPC, NEERC, Southern Subregional Contest Problem L. Stock Trading Robot 水题
- 2013-2014 ACM-ICPC Brazil Subregional Programming Contest 题解
- 2014-2015 ACM-ICPC, Central Europe Regional Contest (CERC 14) [Gym-100543G]
- 2013-2014 ACM-ICPC, NEERC, Moscow Subregional Contest (2013区域赛练习)
- Problem D - Wheels ACM/ICPC Central Europe Regional Contest 2014
- Problem I - Bricks ACM/ICPC Central Europe Regional Contest 2014
- 2015-2016 ACM-ICPC Southwestern Europe Regional Contest (SWERC 15) C题Canvas Painting(单调队列)
- 2013-2014 ACM-ICPC Brazil Subregional Programming Contest