BZOJ 3930 容斥

题目链接


此题的容斥解法首先要基于一个看似神奇但实则显然的定理:
在一个区间长度为 l e n len len的区间任意取n个数,其中n个数不完全相同,则这n个数的gcd一定满足: g c d &lt; = l e n gcd &lt;= len gcd<=len

故我们可以进行递推容斥。
首先假设取的n个数完全相同,若存在其 g c d gcd gcd等于 k k k的情况,则k一定满足:
l &lt; = k &lt; = r l &lt;= k &lt;= r l<=k<=r且n个数只能全是k,故如果满足条件,该方案数一定是1。故可提前特判。

当n个数不完全相同时,设:
a [ i ] : a[i]: a[i] [ l , r ] [l,r] [l,r]区间取 n n n个数,其 g c d = = k ∗ i gcd == k*i gcd==ki的方案数。
a [ 1 ] a[1] a[1] + 特判即为答案。

对于a数组,我们可以倒着递推:
l e n = r k i − ( l − 1 ) k i len =\frac{r}{ki} -\frac{(l-1)}{ki} len=kirki(l1)
a [ i ] = l e n n − l e n − ( a [ 2 i ] + a [ 3 i ] + . . . . ) a[i] = len^n - len - (a[2i] + a[3i] + ....) a[i]=lennlen(a[2i]+a[3i]+....)

减去len是减去取的n个数完全一样的方案数。
故此题可解。


代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int A = 1e5 + 10;
ll a[A];
ll fast_mod(ll n,ll m){
    ll res = 1;
    while(m){
        if(m&1) res = (res*n)%mod;
        n = (n*n)%mod;
        m >>= 1;
    }
    return res;
}
int main(){
    int n,k,l,r;
    ll ans = 0;
    scanf("%d%d%d%d",&n,&k,&l,&r);
    if(l<=k && k<=r) ans++; //特判n个数全选k使gcd == k的情况
    int len = (r-l+1);l--;
    l /= k,r /= k;
    for(int i=len ;i>=1;i--){
        int x = l/i,y = r/i;
        a[i] = (fast_mod(y-x,n) - (y-x))%mod;
        for(int j=2*i ;j<=len ;j+=i) a[i] = (a[i]-a[j])%mod;
    }
    ans = (ans + a[1])%mod;
    if(ans<0) ans+=mod;
    printf("%lld\n",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值