ZROI week3

作业

poj 1091 跳蚤

容斥原理。

考虑能否跳到旁边就是卡牌的\(gcd\)是否是1,可以根据裴蜀定理证明。

考虑正着做十分的麻烦,所以倒着做,也就是用\(M^N - (不合法)\)即可。

不合法显然就是\(gcd\)不为1的情况,那么我们考虑枚举\(gcd\)\((1 \leq gcd \leq 15)\),第\(n + 1\)个数一直是\(m\)所以不用理它。

考虑每个\(gcd\)的贡献,如果所有的都能被整除,那么产生的方案数就是:

\(({m \over gcd})^n\)

表示在小于等于\(m\)的数中有多少能够被当前的\(gcd\)整除,那么每个位置就有这么多数字可以选择,就转化成了容斥原理的问题了,\(dfs\)枚举\(m\)的质因数统计即可。

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
#define int long long
int n,m;
const int MAXN = 1e5 + 10;
int Ans;
int p[MAXN];
int ans;
int div (int now) {
    int res = 0;
    for(int i = 2;i * i <= now; ++i) {
        if(now % i == 0) {
            p[++res] = i;
            now /= i;
            while(now % i == 0) now /= i;
        }
    }
    if(now > 1) p[++res] = now;
    return res;
}


int pow_mod(int a,int b) {
    int res = 1;
    while(b) {
        if(b & 1) res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}

void dfs(int num,int y,int now) {
    if(now > m) return;
    if(num == ans + 1) {
        if(y) {
            if(y & 1) {
                Ans -= pow_mod(m / now,n);
            }
            else {
                Ans += pow_mod(m / now,n);
            }
        }
        return;
    }
    dfs(num + 1,y,now);
    dfs(num + 1,y + 1,now * p[num]);
}

signed main () {
    cin >> n >> m;
    Ans = pow_mod(m,n);
    //cout<<Ans<<endl;
    ans = div(m);
    //cout<<ans<<endl;
    dfs(1,0,1);
    cout<<Ans<<endl;
    return 0;
}

ps:这题为啥不用取模?真是让人难以琢磨。

hdu 5121 just a mistake

期望\(dp\)+容斥原理

题目大意就是让你随机构造一个排列,然后判断是否与集合中的点有连边然后一个一个的连接。

乍一看十分难做,第二眼还是十分难做,做了\(1h23min\)。。。

首先考虑如何统计贡献,一般的方程就是如果第\(i\)\(p_i\)的时候,某些贡献是多少,由于这个问题拓展到了树上,那么就是设\(f_{i,j}\)表示以\(i\)为根的子树中,\(i\)排在第\(j\)位且必须选的方案数。

那么子树中的点如果排在\(i\) 的前面就不能选,因为\(i\)必选,贡献就得减去它。

如果在后面,选了\(i\)之后也不能选它,然后组合数统计答案即可。

具体就是以每个点为根去做搜索,统计出答案之后相加即可,由于期望的线性性。

再来说说具体怎么计算答案,枚举\(y\)这棵子树的1到siz[y]的集合中前\(k\)个插入到\(i\)前面,后面的插在后面,乘上\(f_{i,j}\),在乘上选位置的方案数。

选位置的方案数就是\(C_{n + m}^{n}\)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
const int MAXN = 210;
int C[MAXN][MAXN];
int siz[MAXN];
int f[MAXN][MAXN];
int lnk[MAXN];
int fac[MAXN];
const int mod = 1e9 + 7;
int cnt;
int head[MAXN << 1];
void pre() {
    memset(C,0,sizeof C);
    memset(fac,0,sizeof fac);
    C[0][0] = 1;
    fac[0] = 1;
    for(int i = 1;i <= 200; ++i) {
        C[i][0] = C[i][i] = 1;
        fac[i] = (fac[i - 1] * i) % mod;
        for(int j = 1;j <= i; ++j) {
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
        }
    }
    return;
}
int T,n,x,y;
int ans;
struct edge {
    int to;
    int nxt;
}e[MAXN << 1];
void add(int u,int v) {
    e[++cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
    return;
}

void Add(int u,int v) {
    add(u,v);
    add(v,u);
}

void dfs(int x,int fa) {
    f[x][0] = 0;f[x][1] = 1;
    siz[x] = 1;
    for(int i = head[x];i;i=e[i].nxt) {
        int y = e[i].to;
        if(y == fa) continue;
        dfs(y,x);
        int all_state = fac[siz[y]];
        int tmp = siz[y];
        int sum_state = siz[x] + siz[y];
        siz[x] += siz[y];
        memset(lnk,0,sizeof lnk);
        for(int j = 0;j <= siz[y]; ++j,--tmp) {
            all_state = (all_state + mod - f[y][j]) % mod;
            for(int k = 1;k <= sum_state - siz[y]; ++k) {
                lnk[j + k] = ((lnk[j + k] + all_state * f[x][k] % mod * C[j + k - 1][j] % mod * C[sum_state - j - k][tmp] % mod) % mod + mod) % mod;
            }
        }
        for(int j = 0;j <= sum_state; ++j) {
            f[x][j] = lnk[j];
        }
    }
}
int cas;
signed main () {
    scanf("%lld",&T);
    pre();
    while(T--) {
        scanf("%lld",&n);
        memset(head,0,sizeof head);
        cnt = 0;
        memset(f,0,sizeof f);
        memset(lnk,0,sizeof lnk);
        memset(siz,0,sizeof siz);
        for(int i = 1;i < n; ++i) {
            scanf("%lld %lld",&x,&y);
            Add(x,y);
        }
        ans = 0;
        for(int i = 1;i <= n; ++i) {
            memset(f,0,sizeof f);
            dfs(i,0);
            for(int j = 1;j <= n; ++j) {
                ans = (ans + f[i][j]) % mod;
            }
        }
        printf("Case #%lld: %lld\n",++cas,ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akoasm/p/10215774.html