Codeforces 215E Periodical Numbers 容斥原理

Periodical Numbers

我们先按长度分类对于当前处理的长度k, 我们令 F[ i ] 为有长度为 i 的循环节的方案数。

然后容斥出f[ i ] 表示最小循环节是 i 的方案数, 然后加起来。

#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 100 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

LL l, r;
int a[N];
LL f[N];

LL getVal(int l, int r) {
    LL ans = 0;
    for(int i = l; i <= r; i++) ans *= 2, ans += a[i];
    return ans;
}

LL solve(LL x) {
    if(x <= 1) return 0;
    int tot = 0;
    for(LL i = x; i; i /= 2) a[tot++] = i % 2;
    reverse(a, a + tot);
    vector<int> fac;
    vector<LL> way;
    LL ans = 0;
    for(int i = 2; i < tot; i++) {
        fac.clear(); way.clear();
        for(int j = 1; j < i; j++) {
            if(i % j) continue;
            fac.push_back(j);
        }
        way.resize(SZ(fac));
        for(int j = 0; j < SZ(way); j++)
            way[j] = 1LL << (fac[j] - 1);
        for(int j = 0; j < SZ(way); j++) {
            ans += way[j];
            for(int k = j + 1; k < SZ(way); k++) {
                if(fac[k] % fac[j] == 0) way[k] -= way[j];
            }
        }
    }
    fac.clear(); way.clear();
    for(int i = 1; i < tot; i++) {
        if(tot % i == 0) fac.push_back(i);
    }
    way.resize(SZ(fac));
    for(int j = 0; j < SZ(way); j++) {
        LL val = getVal(0, fac[j] - 1);
        way[j] = max(val - (1ll << (fac[j] - 1)), 0ll);
        bool flag = true;
        for(int k = fac[j]; k + fac[j] - 1 < tot; k += fac[j]) {
            LL tmp = getVal(k, k + fac[j] - 1);
            if(tmp > val) break;
            if(tmp < val) {
                flag = false;
                break;
            }
        }
        way[j] += flag;
    }
    for(int j = 0; j < SZ(way); j++) {
        ans += way[j];
        for(int k = j + 1; k < SZ(way); k++) {
            if(fac[k] % fac[j] == 0) way[k] -= way[j];
        }
    }
    return ans;
}

int main() {
    scanf("%lld%lld", &l, &r);
    printf("%lld", solve(r) - solve(l - 1));
    return 0;
}

/*
*/

猜你喜欢

转载自www.cnblogs.com/CJLHY/p/10833575.html