Codeforces 900D/E

题目链接: http://codeforces.com/contest/900

D题意:给出x, y,求满足下列2个条件的序列数目。
1.Σni=1ai=y
2.gcd(a1,a2,...,an)=x

题解:首先易知,y % x != 0, 则一定不存在这样的数列,答案为0。
   否则数列每个数都除去x,可以转化为求有多少个数列满足gcd为1且和为 yx
设 f(t) 为有多少个数列满足gcd为1且和为 t 。
设 g(t) 为有多少个数列满足和为 t 。
可以得到下式:
           g(t)=d|tf(td)
解法一:记忆化搜索, 直接计算 f(t) ,其中算的时候要容斥一下,初始隔板法想一下便知 mp[x]=2t1,mp[d]

#include 

using namespace std;
typedef long long ll;
const ll mod = 1E9 + 7;
map<int, int>mp;
ll quick(ll a, ll k) //a^k^mod
{
    ll res = 1;
    while(k) {
        if(k & 1) res = res * a % mod;
        k >>= 1;
        a = a * a % mod;
    }
    return res;
}
ll solve(int x)
{
    if(x == 1) return 1;
    if(mp.count(x)) return mp[x];
    mp[x] = quick(2ll, x-1ll);
    for(int i = 2;i * i <= x;i ++) {
        if(x % i == 0) {
            mp[x] = (mp[x] - solve(x / i) + mod) % mod;
            if(i != x / i) {
                mp[x] = (mp[x] - solve(i) + mod) % mod;
            }
        }
    }
    mp[x] = (mp[x] - 1 + mod) % mod;
    return mp[x];
}
int main()
{
    int x, y;
    scanf("%d%d",&x,&y);
    if(y % x) {
        puts("0");
    } else {
        y /= x;
        printf("%lld\n", solve(y));
    }
    return 0;
}

2.莫比乌斯函数。
因为 g(t)=d|tf(td),g(t)=2t1,f(t)=d|tu(d)g(td)

#include 

using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int u(int n)
{
    if(n == 1) return 1;
    int res = 1;
    for(int i = 2;i * i <= n;i ++) {
        if(n % i == 0) {
            res *= -1;
            int k = 0;
            while(n % i == 0) {
                k ++;
                n /= i;
                if(k > 1) {
                    return 0;
                }
            }
        }
    }
    if(n > 1) res *= -1;
    return res;
}
ll qmod(ll a, ll k) // a^k
{
    ll res = 1;
    while(k) {
        if(k & 1) res = res * a % mod;
        k >>= 1;
        a = a * a % mod;
    }
    return res;
}
ll gao(ll x)
{
    ll res = 0;
    for(int i = 1;i * i <= x;i ++) {
        if(x % i == 0) {
            res = (res + qmod(2ll, x/i-1ll) * u(i)) % mod;
            if(i != x / i) {
                res = (res + qmod(2ll, i - 1ll) * u(x / i)) % mod;
            }
        }
    } return res;
}
int main()
{
    int x, y;
    scanf("%d%d",&x,&y);
    if(y % x) {
        return puts("0"), 0;
    } else {
        return printf("%lld\n",(gao(y/x)%mod+mod)%mod), 0;
    }
}

————————————————————————————————————————————

————————————————————————————————————————————

E题意:没坑点,自己读下即可。
题解:可以求出连续的从 i 开始 abab… 数量 ai 。
求出问号前缀和 pre[i] 。
然后就变成dp了。
dp[i+1]=max(dp[i+1],dp[i])

dp[i+m]=max(dp[i+m],pair(dp[i]+1,dp[i]+pre[m]pre[i]))

答案就是 dp[n].second
max的定义是数量最大消耗问号最小(注意重载)。

#include 

using namespace std;
const int N = 1E5 + 7;
struct node
{
    int c, w;
    node():c(0),w(0){}
    node(int a,int b):c(a),w(b){}
    bool operator < (const node & x) const {
        return c < x.c || c == x.c && w > x.w;
    }
}dp[N];
int a[N], b[N], pre[N];
char s[N];
int sum(int l, int r)
{
    return pre[r] - pre[l-1];
}
int main()
{
    int n, m;
    scanf("%d%s%d",&n,s+1,&m);
    for(int i = n;i >= 1;i --) {
        if(s[i] == 'a') {
            a[i] = b[i+1] + 1;
            b[i] = 0;
        } else if(s[i] == 'b') {
            b[i] = a[i+1] + 1;
            a[i] = 0;
        } else {
            a[i] = b[i+1] + 1;
            b[i] = a[i+1] + 1;
        }
    }
    for(int i = 1;i <= n;i ++) pre[i] = pre[i-1] + (s[i] == '?');
    for(int i = 0;i < n;i ++) {
        dp[i+1] = max(dp[i+1], dp[i]);
        if(i + m <= n && a[i+1] >= m) {
            dp[i+m] = max(dp[i+m], node(dp[i].c+1, dp[i].w+sum(i+1,i+m)));
        }
    }
    printf("%d\n",dp[n].w);
    return 0;
}

你可能感兴趣的:(莫比乌斯反演,动态规划)