bzoj5019: [Snoi2017]遗失的答案

来源:互联网 发布:python图片验证码识别 编辑:程序博客网 时间:2024/04/25 18:13

前言

这题一开始觉得很难写。。
实际上如果你先把暴力写好,再修改,还是蛮好写的
写了不到2h就写过了。。

题解

我们可以吧LG都分解质因数
显然,不同的质因数最多只有8个
然后设一个质因数i,他在L里面的次数是a,在G里面的次数是b
那么他选的数,对于i的次数,只能是a到b之间
那么就是说可行的数是可以预先找出来的
然后有一个结论(可以打表证明),可行的数,不超过1000个
然后你想把可行的数都找出来
然后你现在要在里面找一些数满足条件:对于一个质因数i,必须至少有一个数,使得i在他里面的次数是a。然后至少有一个数,使得i在他里面的次数是b
问你有多少种方案
其实就相当于有28个限制,要你满足
然后这个就可以容斥了
怎么容斥就自己想想就好了。。

CODE:

#include<cstdio>#include<cstdlib>#include<algorithm>#include<iostream>#include<cstring>#include<bitset>using namespace std;typedef long long LL;const int MOD=1000000007;const int N=100005;const int K=1005;const int M=20;int n,g,l;//1~n   最大公约数是g,最小公倍数是l int pri[N],tot=0;int a[N],b[N];//两个东西分别有多少个int c[K],lalal=0;//有哪些数是合法的 int t[M],h[M];//这个质数的两个边界LL pow (int x,LL y){    if (y<0) return 0;    if (y==0) return 1;    if (y==1) return x;    LL lalal=pow(x,y>>1);    lalal=lalal*lalal%MOD;    if (y&1) lalal=lalal*x%MOD;    return lalal;}void prepare (){    int L=l,G=g;    for (int u=2;u*u<=L;u++)        if (L%u==0)        {            pri[++tot]=u;            while (L%u==0)  {a[tot]++;L/=u;}        }    if (L!=1)   {pri[++tot]=L;a[tot]=1;}    for (int u=1;u<=tot;u++)        while (G%pri[u]==0)            {G/=pri[u];b[u]++;}    for (int u=1;u<=tot;u++)    {        int shen=1;        for (int i=1;i<=b[u];i++)   shen=shen*pri[u];        t[u]=shen;        for (int i=b[u]+1;i<=a[u];i++) shen=shen*pri[u];        h[u]=shen;    }}void dfs (int x,int y)//选到第几个因数    当前的值是什么 {    if (y>n) return ;    if (x>tot)  {c[++lalal]=y;return ;}    int shen=1;    for (int u=1;u<=b[x];u++)   shen=shen*pri[x];    for (int u=b[x];u<=a[x];u++)    {        dfs(x+1,y*shen);        shen=shen*pri[x];    }}LL ans[K];void find (int x){    int l=1,r=lalal;    while (l<=r)    {        int mid=(l+r)>>1;        if (c[mid]==x) {printf("%lld\n",ans[mid]);return ;}        if (c[mid]>x) r=mid-1;        if (c[mid]<x) l=mid+1;    }    printf("0\n");    return ;}bool ok[N];//这个数还在不在考虑范围内bitset<K> s[1<<20];LL o[1<<20];//有多少个 void dfs2 (int x,int y,int z,int v)//我们现在处理到第几个条件   要更新的是哪一个   当前已经有多少个至少是不满足的 {    if (x>2*tot)    {        if (s[z][y]==false) return ;        if ((2*tot-v)%2==0) ans[y]=(ans[y]+o[z])%MOD;        else ans[y]=((ans[y]-o[z])%MOD+MOD)%MOD;        return ;    }    dfs2(x+1,y,z<<1,v);     dfs2(x+1,y,(z<<1)+1,v+1);}void dfs1 (int x,int z){    if (x>2*tot)    {        for (int u=1;u<=lalal;u++) s[z][u]=true;        for (int u=1;u<=tot;u++)            if ((z&(1<<u-1))!=0)//如果这个条件是不满足的                   for (int i=1;i<=lalal;i++)                    if ((c[i]/t[u])%pri[u]!=0)//如果这个是有底线的                        s[z][i]=false;        for (int u=tot+1;u<=tot*2;u++)            if ((z&(1<<u-1))!=0)//如果这个条件是不满足的                for (int i=1;i<=lalal;i++)                    if (c[i]%h[u-tot]==0)//如果这个是有顶线的                        s[z][i]=false;        for (int u=1;u<=lalal;u++)            if (s[z][u]==true)                o[z]++;        o[z]=pow(2,o[z]-1);        return ;    }    dfs1(x+1,z<<1);     dfs1(x+1,(z<<1)+1);}int main(){    scanf("%d%d%d",&n,&g,&l);    if (l%g!=0)    {        int q;        scanf("%d",&q);        while (q--) printf("0\n");        return 0;    }    prepare();    dfs(1,1);    sort(c+1,c+1+lalal);    dfs1(1,0);    for (int u=1;u<=lalal;u++)        dfs2(1,u,0,0);    int q;    scanf("%d",&q);    while (q--)    {        int x;        scanf("%d",&x);        find(x);    }    return 0;}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 作文素材高考版 高中作文素材摘抄 语文素材积累摘抄 语文作文素材 国庆黑板报素材 国庆图片素材 高中语文素材积累摘抄 国庆作文素材 作文素材高考 好的作文素材 高中作文素材精华本 议论文素材大全 高中议论文素材 广告图片素材 高三作文素材 图案设计素材 高考作文素材积累 人物素材积累 高中作文素材大全 素材是什么意思 语文素材大全 素材网站大全 平面设计素材网站 矢量图素材网 设计名片素材 名片设计素材网 会声会影素材 景观素材网站 名片设计 素材 婚礼素材收集者 企业网站素材 淘宝主图素材 创意海报素材 设计师名片素材 网页制作素材 素材网矢量图 设计素材网站大全 psd 平面设计网站 标志图 平面广告设计