牛牛小数点 题解(结论+容斥)
作者:互联网
题目链接
题目思路
感觉就是两个结论(或许打表可以发现
2 否则,x是循环的,且循环开始于小数点后第1+max(p2,p5)位,其中p2表示表示质因数分解形式下2的指数项,p5表示质因数分解下5的指数项。即f(x)=1+max(p2,p5)
第一个结论,感觉好理解一点 就是可以使得分子分母进行约分,使得分母为\(10^i\)得到不循环小数
第二点的话我也不太会
然后知道结论的话设\(dp[i][j]\)表示\(1-n\)中\(2^i*5^j\)的倍数有多少个
然后容斥
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=3e5+5,inf=0x3f3f3f3f,mod=998244353;
const double eps=1e-6;
ll l,r;
ll dp[100][100];
ll cal(ll n){
memset(dp,0,sizeof(dp));
// dp[i][j] 表示1-n里面有多少个树为2^i*5^j的倍数
ll x=1,y=1;
for(int i=0;i<=50;i++){
for(int j=0;j<=25;j++){
if(y>n) break;
dp[i][j]=n/y;
y=y*5;
}
x=x*2;
y=x;
}
ll ans=0;
for(int i=0;i<=50;i++){
for(int j=0;j<=25;j++){
ll num=dp[i][j]-dp[i+1][j]-dp[i][j+1]+dp[i+1][j+1]-1;
// 减1的原因是删除只2^i*5^j
if(num<=0) continue;
ans=(ans+1ll*(max(i,j)+1)*num%mod)%mod;
}
}
return ans;
}
signed main(){
int _;scanf("%d",&_);
while(_--){
scanf("%lld%lld",&l,&r);
ll ans=((cal(r)-cal(l-1))%mod+mod)%mod;
printf("%lld\n",ans);
}
return 0;
}
标签:p2,结论,因数分解,p5,牛牛,题解,容斥,max,define 来源: https://www.cnblogs.com/hunxuewangzi/p/15346323.html