JZOJ5796. 2018.08.10【2018提高组】模拟A组&省选 划分(二项式反演容斥+拓展GCD)

description

  • m m 个数a[1..m],对于 a[i] a [ i ] ,我们可以知道 ka[i]i=(k1)a[i]+1x[i]ka[i]<=n ∑ i = ( k − 1 ) ∗ a [ i ] + 1 k ∗ a [ i ] x [ i ] ( k ∗ a [ i ] <= n ) 以及
  • 前n个数的和,问我们能确定几个 x[i] x [ i ]

40points

  • sum[i]=ni=1x[i] s u m [ i ] = ∑ i = 1 n x [ i ]
  • 如果知道 sum[i]sum[i1],x[i] s u m [ i ] 和 s u m [ i − 1 ] , 那 么 我 们 就 可 以 确 定 x [ i ]
  • 结论显然
  • [l..r],[l..i1],[i+1..r]x[i] 如 果 知 道 区 间 [ l . . r ] , 区 间 [ l . . i − 1 ] , 区 间 [ i + 1.. r ] 各 自 的 和 , 那 也 可 以 知 道 x [ i ]
  • [i+1..r][x..i], 但 区 间 [ i + 1.. r ] 前 面 区 间 一 定 有 区 间 [ x . . i ] , 所 以 结 论 证 毕
  • a[i]bz 所 以 我 们 对 每 个 a [ i ] 把 他 的 倍 数 b z 一 下 , 这 说 明 他 的 倍 数 的 前 缀 和 可 以 确 定
  • Omi=1na[i]+n O ( ∑ i = 1 m ⌊ n a [ i ] ⌋ + n )

100points

  • x 对 于 x 能 否 被 确 定 , 显 然 可 以 列 方 程
  • x mod a[i]=0 x   m o d   a [ i ] = 0
  • x mod a[j]=1 x   m o d   a [ j ] = 1
  • m2 是 不 是 列 m 2 个 方 程 , 求 可 行 解 就 可 以 了 ? ! !
  • 会 算 重 ! ! !
  • i0(A)1B 那 么 我 们 就 枚 举 第 i 个 数 是 选 结 果 为 0 的 方 程 ( 放 A 集 合 ) , 结 果 为 1 的 方 程 ( 放 B 集 合 ) , 还 是 不 选
  • lcm 然 后 列 方 程 后 对 于 结 果 相 同 的 , 可 以 用 l c m 来 合 并
  • gcd(1)|A|+|B| 最 后 用 拓 展 g c d 算 出 解 的 个 数 ∗ ( − 1 ) | A | + | B |
  • x1 证 如 果 x 合 法 , 只 会 算 1 次
  • |A|i=1Ci|A||B|i=1Ci|B|(1)i+j ∑ i = 1 | A | C | A | i ∑ i = 1 | B | C | B | i ( − 1 ) i + j
  • =|A|i=1Ci|A|(1)i|B|j=1Cj|B|(1)j = ∑ i = 1 | A | C | A | i ( − 1 ) i ∑ j = 1 | B | C | B | j ( − 1 ) j
  • =((11)|A|1)((11)|B|1) = ( ( 1 − 1 ) | A | − 1 ) ∗ ( ( 1 − 1 ) | B | − 1 )
  • =1 = 1
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const ll maxN=20;
ll n,m,i,j,ii,jj,sum1,ans,a[maxN],bz;
ll gcd(ll x,ll y){
    return (x%y==0)?y:gcd(y,x%y);
} 
ll lcm(ll x,ll y){
    i=gcd(x,y);
    return x/i*y;
}
void exgcd(ll xx,ll yy){
    if (yy==0){
        i=1,j=0;
        return;
    }
    exgcd(yy,xx%yy);
    ii=i,jj=j;
    i=-jj,
    j=-ii-(xx/yy)*jj;
}
void dfs(ll t,ll x,ll y,ll sum){
    if (gcd(x,y)!=1) return;
    if (x>n || y>n) return;
    if (t>m){
        if (x==1 || y==1) return;
        exgcd(x,y);
        i=(i%y+y)%y;
        j=n/x;
        if (j<i){
            return;
        }
        sum1=(j-i)/y;
        sum1+=(j>=i);
        ans+=sum*sum1;
        if (j*x==n && (j-i)%y==0){
            bz=0;
        }
        return;
    }
    dfs(t+1,lcm(a[t],x),y,-sum);
    dfs(t+1,x,lcm(a[t],y),-sum);
    dfs(t+1,x,y,sum);
}
int main(){
    freopen("sazetak.in","r",stdin);
    freopen("sazetak.out","w",stdout);
    scanf("%lld%lld",&n,&m);    
    fo(i,1,m) scanf("%lld",&a[i]);
    bz=1;
    dfs(1,1,1,1);
    fo(i,1,m)
        if ((n-1)%a[i]==0) ans+=bz; 
    printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值