• “玲珑杯”线上赛 Round #17 河南专场 B:震惊,99%+的中国人都会算错的问题(容斥计算)


    传送门

    题意

    分析

    是一道稍微变形的容斥题目,容斥一般的公式

    [ans=sum_iAi-sum_{i<j}{Ai∩Aj}+sum_{i<j<k}{Ai∩Aj∩Ak}+... ]

    但是这道题只要奇数次数的,那么对于第k项乘以一个系数(2^{k-1})
    具体见代码

    trick

    如果在每次dfs中for循环前加一个判断:if(lcm<=n)...
    时间会从1000ms降到20ms

    代码

    #include<cstdio>
    
    #define ll long long
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define R(i,a,b) for(int i=a;i<b;++i)
    #define mem(a,b) memset(a,b,sizeof(a))
    //#pragma comment(linker, "/STACK:102400000,102400000")
    //inline void read(int &x){x=0; char ch=getchar();while(ch<'0') ch=getchar();while(ch>='0'){x=x*10+ch-48; ch=getchar();}}
    inline ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
    int t,n,m;
    ll lcm,a[16],ans;
    /*
    举个栗子,如A,B,C,那么第一次dfs会计算A,AB,AC,ABC的值,第二次dfs会计算B,BC,第三次dfs会计算C
    ,希望大家能够理解
    */
    void dfs(int cur,ll lcm,int num)//当前第cur个,需要乘的系数为2^(num-1)
    {
    	lcm=a[cur]/gcd(a[cur],lcm)*lcm;
    	if(num&1) ans+=n/lcm*(1ll<<(num-1));
    	else ans-=n/lcm*(1ll<<(num-1));
    	if(lcm<=n) for(int i=cur+1;i<m;++i)  dfs(i,lcm,num+1);
    }
    int main()
    {
        for(scanf("%d",&t);t--;)
        {
        	scanf("%d %d",&n,&m);
        	ans=0;
        	for(int i=0;i<m;++i) scanf("%lld",a+i);
        	for(int i=0;i<m;++i)  dfs(i,a[i],1);
        	printf("%lld
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    手把手教您玩转信用卡 如何“以卡养卡”合法“套现”
    267家已获第三方许可机构名单查询
    C#生成图片验证码
    File I/O
    文件上传代码
    集合框架
    接口
    多态
    封装
    jsp做成mvc模式的代码
  • 原文地址:https://www.cnblogs.com/chendl111/p/7074171.html
Copyright © 2020-2023  润新知