bzoj 1853: [Scoi2010]幸运数字
1853: [Scoi2010]幸运数字
2017-08-27
Description
Input
Output
Sample Input
1 10
【样例输入2】
1234 4321
23333 6666666
Sample Output
2
【样例输出2】
809
【数据范围】
对于30%的数据,保证1 < =a < =b < =1000000
对于100%的数据,保证1 < =a < =b < =10000000000
这个题先进行一遍dfs找到所有满足条件的数(只有‘6’|‘8’)的数(并且小于右端点)。放进集合A
然后再集合A中删去所有A[i]>A[j]且A[i]%A[j]==0的数。why?不想证
那么咱们怎么根据删去数后的A快速求出在区间有多少呢?
显然在区间[1,r]的区间能整除k的数只有[r/k]。
但是这样又会把任意两个数的最小公倍数算两次>_>(wa)
所以我们还要算一遍任意两数的最小公倍数,减去它们!然后就又算少了QwQ.
↑就是为什么要去掉部分数的原因poi
递归来求不同数的lcm,不停的加减,最后就A掉了x
两个数a,b的lcm=a*b/gcd(a,b);gcd(a,b)<=a,b
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #define ll long long using namespace std; int cnt; ll gcd(ll x,ll y){ if(y==0)return x; else return gcd(y,x%y); } ll l,r,n,m,ans; ll a[5000],b[5000]; bool rem[5000]; void add(int x,ll y){ if(y>r)return; if(x)n++,a[n]=y; add(x+1,y*10+6); add(x+1,y*10+8); } void dfs(int x,int y,ll now){ if(x>m){ if(y&1)ans+=r/now-l/now; else if(y)ans-=r/now-l/now; return ; } dfs(x+1,y,now); ll re=now/gcd(now,a[x]); if(((double)re*a[x])<=r) dfs(x+1,y+1,re*a[x]); } int main(){ cin>>l>>r;l--; add(0,0); sort(a+1,a+1+n); for(int i=1;i<=n;++i){ if(!rem[i]){ m++,b[m]=a[i]; for(int j=i+1;j<=n;j++) if(!(a[j]%a[i]))rem[j]=1; } } for(int i=1;i<=m;i++){a[m+1-i]=b[i];} dfs(1,0,1); cout<<ans; return 0; }
符号优先有毒
by:s_a_b_e_r
先求出所有lucky number丢进数组a
然后去掉一些多余的数字
比如6和666都是lucky number
但是666是6的倍数
所以666可以去掉
why?不想证你不想证我来证
666作为一个luckynumber,因为是luckynumber6的倍数,所以它同时也是一个近似luckynumber
所以把它删去之后它在之后的计算中还会被重新算回来
所以出于复杂度考虑就把它删去了……666同学走好x
接着dfs一遍计算答案个数
dfs(x,y,z)表示目前处理到luckynumber第x个数,已经选了y个数,这y个数的lcm(最小公倍数)是z
每次把ans加上每个数,减去每两个数的lcm,加上每三个数的lcm,减去每四个数的lcm……
这样,就OK了w
附代码
#include<iostream> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int N=10001; ll l,r,ans,a[N],b[N]; int cnt,n; bool vis[N]; ll gcd(ll a,ll b){if(b==0)return a;return gcd(b,a%b);} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} void lun(int x,ll y) { if(y>r)return; if(x>0)a[++cnt]=y; lun(x+1,y*10+6); lun(x+1,y*10+8); } void dfs(int x,int y,ll z) { if(x>n) { if(y%2)ans+=r/z - (l-1)/z; else if(y)ans-=r/z - (l-1)/z; return; } dfs(x+1,y,z); ll t=z/gcd(a[x],z); if(((double)a[x]*t)<=r)dfs(x+1,y+1,a[x]*t); } int main() { cin>>l>>r; lun(0,0); sort(a+1,a+cnt+1); for(int i=1;i<=cnt;++i) { if(vis[i])continue; b[++n]=a[i]; for(int j=i+1;j<=cnt;++j) if(!(a[j]%b[n]))vis[j]=1; } for(int i=1;i<=n;++i)a[n-i+1]=b[i]; dfs(1,0,1); cout<<ans<<endl; return 0; }
符号优先有毒+1,'!'优先级>'%',害的我俩TLE好多发qwq
by:wypx
s:感觉steam那个桌面好棒啊
w:日常沉迷小姐姐x