CDOJ1544 [“玲瓏杯” 線上賽Round #17 B] 當鹹魚也要按照基本法(容斥原理 湊係數)

(CDOJ1544 [“玲瓏杯” 線上賽Round #17 B] 當鹹魚也要按照基本法

原題地址
http://acm.uestc.edu.cn/#/problem/show/1544
http://www.ifrog.cc/acm/problem/1138

題意:
zhu有N條鹹魚(標號從1到N),每條鹹魚都有一個鹹魚值Ki,初始時所有Ki都是0.
zhu有M個鹹數,對於每個鹹數x,他都會讓所有滿足標號是x倍數的鹹魚的鹹魚值異或上1.
zhu現在想知道經過了這M個鹹數的篩選之後,最終有多少條的鹹魚的鹹魚值是1?

數據範圍
1≤T≤1000,1≤N≤1e9,1≤M≤15,1≤鹹數≤2∗1e5

題解:
原題意即:
給定m 個數a1…am, 統計[1,n] 的整數中, 滿足a1…am 中有奇數個數整除它的數的個數。
N很大,而M才15,要從M下手,
易得到至少整除集合s的數的個數,考慮容斥。
當然這要求有奇數個數整除它,容斥係數似乎不大好確定。

根據要求得到關於容斥係數的式子:

i=0k(ki)fi=k mod 2

f(i) 可以m2 推。(當然打表或者手推可以發現是fi=[i0](2)i1
然後2m 枚舉子集乘上相應的容斥係數,直接容斥即可。

(longlong不開WA一天)

代碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int N=20;
int T,m,f[N],C[N][N],a[N];
int cnt[100005],lg[100005];
LL n,lcm[100005],ans=0;
LL gcd(LL x,LL y) {return y==0?x:gcd(y,x%y);}
int main()
{
    scanf("%d",&T);
    for(int i=0;i<=16;i++) lg[1<<i]=i;
    for(int i=0;i<=16;i++) for(int j=0;j<=i;j++) if(j==0||i==j) C[i][j]=1;else C[i][j]=C[i-1][j-1]+C[i-1][j];
    f[1]=1;
    for(int i=2;i<=16;i++)
    {
        int s=0; for(int j=1;j<i;j++) s+=C[i][j]*f[j];
        f[i]=i%2-s;
    }
    while(T--)
    {
        scanf("%lld%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d",&a[i]);
        int top=1<<m; ans=0;
        for(int s=1;s<top;s++)
        {
            int x=(s&(-s)); int ss=s^x;
            if(!ss) {cnt[s]=1; lcm[s]=1LL*a[lg[x]+1];}
            else if(lcm[ss]==-1) {lcm[s]=-1; cnt[s]=cnt[ss]+1; continue;}
            else {cnt[s]=cnt[ss]+1; lcm[s]=1LL*lcm[ss]*(1LL*a[lg[x]+1]/gcd(lcm[ss],1LL*a[lg[x]+1]));}
            ans+=1LL*f[cnt[s]]*1LL*(1LL*n/lcm[s]);
            if(lcm[s]>n) lcm[s]=-1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

發佈了203 篇原創文章 · 獲贊 43 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章