ACM-ICPC 2018 沈阳赛区网络预赛 G.Spare Tire (容斥)

Spare Tire

A sequence of integer {an}\lbrace a_n \rbrace{an​} can be expressed as:

an={0,n=02,n=13an−1−an−22+n+1,n>1\displaystyle a_n = \left{

0,2,3an1an22+n+1,n=0n=1n>1 0 , n = 0 2 , n = 1 3 a n − 1 − a n − 2 2 + n + 1 , n > 1
\right. an​=⎩⎨⎧​0,2,23an−1​−an−2​​+n+1,​n=0n=1n>1​
Now there are two integers nnn and mmm. I’m a pretty girl. I want to find all b1,b2,b3⋯bpb_1,b_2,b_3\cdots b_pb1​,b2​,b3​⋯bp​ that 1≤bi≤n1\leq b_i \leq n1≤bi​≤n and bib_ibi​ is relatively-prime with the integer mmm. And then calculate:

∑i=1pabi\displaystyle \sum_{i=1}^{p}a_{b_i} i=1∑p​abi​​
But I have no time to solve this problem because I am going to date my boyfriend soon. So can you help me?

Input

Input contains multiple test cases ( about 150001500015000 ). Each case contains two integers nnn and mmm. 1≤n,m≤1081\leq n,m \leq 10^81≤n,m≤108.
Output

For each test case, print the answer of my question(after mod 1,000,000,0071,000,000,0071,000,000,007).
Hint

In the all integers from 111 to 444, 111 and 333 is relatively-prime with the integer 444. So the answer is a1+a3=14a_1+a_3=14a1​+a3​=14.
样例输入

4 4

样例输出

14

题目来源

ACM-ICPC 2018 沈阳赛区网络预赛

题意:

已知 ai a i 序列,给你一个n和m求小于n与m互质的数作为a序列的下标的和

分析:

通过打表发现 ai a i 序列就等于 ai=i(i+1) a i = i ( i + 1 ) 那么原问题可以转化为求解

i=1ni(i+1)[gcd(i,m)==1] ∑ i = 1 n i ( i + 1 ) [ g c d ( i , m ) == 1 ]

因此可以使用容斥定理得到

=i=1ni(i+1)d|n,d|md(d+1) 原 式 = ∑ i = 1 n i ( i + 1 ) − ∑ d | n , d | m d ( d + 1 )

因为 i(i+1)=i2+i i ( i + 1 ) = i 2 + i

i=1ni2+i=n(n+1)(2n+1)6+n(n+1)2 ∑ i = 1 n i 2 + i = n ( n + 1 ) ( 2 n + 1 ) 6 + n ( n + 1 ) 2

那么后面部分怎么求和呢

我们发现实际上就是找到mn的某个公因数d,然后就是倍数求和嘛

假设最小公因数为d,那么就是

dnd(d+1)=i=1[nd]id(id+1)=i=1[nd]d2i2+di=d2n(n+1)(2n+1)6+dn(n+1)2 ∑ d n d ( d + 1 ) = ∑ i = 1 [ n d ] i d ( i d + 1 ) = ∑ i = 1 [ n d ] d 2 i 2 + d i = d 2 n ( n + 1 ) ( 2 n + 1 ) 6 + d n ( n + 1 ) 2

这样我们可以将m进行素因子分解,然后二进制枚举组合出所有本质不同的最小的公因数,然后套用上式再利用容斥定理求解

code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const ll inv6 = 166666668;
const ll inv2 = 500000004;
ll a[10005];
ll clac(ll n,ll i){
    n /= i;
    return (n % mod * (n + 1) % mod * (2 * n + 1) % mod * inv6 % mod * i % mod * i % mod + n % mod * (n + 1) % mod * inv2 % mod * i % mod) % mod;
}
int main(){
    ll n,m;
    while(~scanf("%lld%lld",&n,&m)){
        int cnt = 0;
        for(int i = 2; i * i <= m; i++){
            if(m % i == 0){
                a[cnt++] = i;
                while(m % i == 0)
                    m /= i;
            }
        }
        if(m != 1)
            a[cnt++] = m;
        ll ans = clac(n,1);
        ll ans2 = 0;
        for(int i = 1; i < (1 << cnt); i++){
            int flag = 0;
            ll tmp = 1;
            for(int j = 0; j < cnt; j++){
                if(i & (1 << j)){
                    flag++;
                    tmp = tmp * a[j] % mod;
                }
            }
            tmp = clac(n,tmp);
            if(flag & 1) ans2 = (ans2 % mod + tmp % mod) % mod;
            else ans2 = (ans2 % mod - tmp % mod + mod) % mod;
        }
        printf("%lld\n",(ans % mod - ans2 % mod + mod) % mod);
    }
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值