2020牛客暑期多校训练营第一场

(拿来监督自己补补题)

J.Easy Integration

题目描述
给定一个 n n n,求 ∫ 0 1 ( x − x 2 ) n d x \int_{0}^{1} (x-x^2)^n dx 01(xx2)ndx 约分后的答案。
思路
在不知道公式的情况下,这是一个规律题。可以通过对前几项做计算可以发现,以 1 , 2 , 3 1,2,3 1,2,3为例
n = 1 , r e s = 1 2 ∗ 3 n = 1,res=\frac{1}{2*3} n=1,res=231等价于 1 2 ∗ 3 \frac{1}{2*3} 231
n = 2 , r e s = 2 3 ∗ 4 ∗ 5 n=2,res=\frac{2}{3*4*5} n=2,res=3452等价于 1 ∗ 2 3 ∗ 4 ∗ 5 \frac{1*2}{3*4*5} 34512
n = 3 , r e s = 6 4 ∗ 5 ∗ 6 ∗ 7 n=3,res=\frac{6}{4*5*6*7} n=3,res=45676等价于 1 ∗ 2 ∗ 3 4 ∗ 5 ∗ 6 ∗ 7 \frac{1*2*3}{4*5*6*7} 4567123
所以可以很快得出规律公式
( n ! ) 2 ( 2 n + 1 ) ! \frac{(n!)^2}{(2n+1)!} (2n+1)!(n!)2
正确证明
已知有贝塔函数 B ( P , Q ) = ∫ 0 1 x P − 1 ( 1 − x ) Q − 1 d x B(P,Q)=\int_{0}^{1} x^{P-1}(1-x)^{Q-1} dx B(P,Q)=01xP1(1x)Q1dx
贝塔函数与伽马函数的关系
B ( P , Q ) = P + Q P Q C P + Q P = 1 Q C P + Q − 1 P − 1 B(P,Q)=\frac{P+Q}{PQC_{P+Q}^P}=\frac{1}{QC_{P+Q-1}^{P-1}} B(P,Q)=PQCP+QPP+Q=QCP+Q1P11
文献资料链接

所以原公式 ∫ 0 1 ( x − x 2 ) n d x = ∫ 0 1 x n ( 1 − x ) n d x = 1 ( n + 1 ) C 2 n + 1 n \int_{0}^{1} (x-x^2)^n dx=\int_{0}^{1} x^n(1-x)^n dx=\frac{1}{{(n+1)}C_{2n+1}^{n}} 01(xx2)ndx=01xn(1x)ndx=(n+1)C2n+1n1
代码

#include<bits/stdc++.h>
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
 
const int p = 998244353;
const int N = 2e6 + 10;
LL fac[N], infac[N];
LL n;
 
LL kpow(LL a, LL n) {
    LL res = 1;
    while(n) {
        if(n & 1) res = (res * a) % p;
        n >>= 1;
        a = (a * a) % p;
    }
    return res;
}
 
void init() {
    fac[0] = infac[0] = 1;
    for(int i = 1; i < N; i++) {
        fac[i] = (fac[i - 1] * i) % p;
        infac[i] = (infac[i - 1] * kpow(i, p - 2)) % p;
    }
}

LL C(int a, int b) {
    return fac[a] * infac[b] % p * infac[a - b] % p;
}

void solve() {
    printf("%lld\n", kpow(n + 1, p - 2) * kpow(C(2 * n + 1, n), p - 2) % p);
}
 
int main() {
    init();
    // freopen("in.txt", "r", stdin);
    //int t; cin >> t; while(t--)
    while(~scanf("%d",&n))
    solve();
    return 0;
}

F Infinite String Comparision

题目描述
给定两个字符串a,b。比较无限个字符串a拼接和无限个字符串b拼接的大小。
思路
看到一个很nb的做法,仔细想了想,发现这个思路tql。
比较a + b和 b + a的大小。
字符串a,b长度相等就没什么可比性了。
这里假设strlen(a) < strlen(b)
如果前 len(a) 个字符有大小不相等的,那一定输出大于或小于了。但如果b字符串前len(a)个字母与a相等 ,就相当于将b字符串第len(a)+1位与字符串a的第1位相比较,因为b字符串前len(a)个字符与字符串a相同,就等价于b字符串的第len(a)+1位与其第一位比较是否相同。b字符串后面接a也是相同道理。自己的思维还是太拉跨了
代码

#include<bits/stdc++.h>
using namespace std;

int main() {
//    freopen("in.txt", "r", stdin);
    string a, b;
    while(cin >> a >> b) {
        string A = a + b;
        string B = b + a;
        if(A > B) puts(">");
        else if(A == B) puts("=");
        else puts("<");
    }
    return 0;
}

I 1 or 2

题目描述
给定一个 n n n个点, m m m条边的无向图,是否存在一个子图,使其每个点的度数为 d i d_i di
进阶版题目 hdu3551
思路
问是否存在一个子图,考虑删边。每删除一条边会将两个点的度减一。将每个点的度拆分成一个个点。然后对图进行拆分,一条边所对应的点拆分成两个点 u u u v v v ,将他们所对应的度数的点与其对应的点连边。
比赛的时候想到过二分图最大匹配,将度数拆成的点与边拆的两个点一一匹配,若想要成立,边拆成的点一定要大于等于点的度数拆成的点。如果只进行二分图匹配,那么边所产生的两个点 u u u v v v 可能并不能完全匹配二次。
所以在匹配完度数的拆点和点之后,要去看剩下没有被完全占用的边是否一次都没有被占用,等价于剩下没有被占用的边的两个点也都需要两两匹配,所以需要一般图匹配,也就是带花树算法。
代码
带花树算法模板抄kuangbin的,只有 C r e a t G r a p h ( ) CreatGraph() CreatGraph()函数和 P r i n t M a t c h ( ) PrintMatch() PrintMatch()函数改了改

#include<bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
typedef long long LL;
const int N = 110, M = 410;
vector<int> e[N];
int n, m;
int d[N];
int idx;
PII edge[N];
vector<int> du[N];

bool Graph[M][M];
int Match[M];
bool InQueue[M], InPath[M], InBlossom[M];
int Head, Tail;
int Queue[M];
int Start, Finish;
int NewBase;
int Father[M], Base[M];
int Count;

void init() {
    for(int i = 1; i <= n; i++) {
        e[i].clear();
        du[i].clear();
    }
    memset(d, 0, sizeof d);
    memset(edge, 0, sizeof edge);
    memset(Graph, 0, sizeof Graph);
    memset(Match, 0, sizeof Match);
    memset(InQueue, 0, sizeof InQueue);
    memset(InPath, 0, sizeof InPath);
    memset(InBlossom, 0, sizeof InBlossom);
    memset(Queue, 0, sizeof Queue);
    memset(Father, 0, sizeof Father);
    memset(Base, 0, sizeof Base);
    Count = Start = Finish = NewBase = Head = Tail = idx = 0;
}

void CreatGraph() {
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= d[i]; j++) {
            du[i].push_back(++idx);
        }
    }
    for(int i = 1; i <= m; i++) {
        int u = edge[i].first, v = edge[i].second;
        int a = ++idx, b = ++idx;
        Graph[a][b] = Graph[b][a] = 1;
        for(int j = 0; j < du[u].size(); j++) {
            int x = du[u][j];
            Graph[a][x] = Graph[x][a] = 1;
        }
        for(int j = 0; j < du[v].size(); j++) {
            int x = du[v][j];
            Graph[b][x] = Graph[x][b] = 1;
        }
    }
}


void Push(int u) {
    Queue[Tail] = u;
    Tail++;
    InQueue[u] = true;
}

int Pop() {
    int res = Queue[Head];
    Head++;
    return res;
}

int FindCommonAncestor(int u, int v) {
    memset(InPath, false, sizeof(InPath));
    while(true) {
        u = Base[u];
        InPath[u] = true;
        if(u == Start) break;
        u = Father[Match[u]];
    }
    while(true) {
        v = Base[v];
        if(InPath[v]) break;
        v = Father[Match[v]];
    }
    return v;
}

void ResetTrace(int u) {
    int v;
    while(Base[u] != NewBase) {
        v = Match[u];
        InBlossom[Base[u]] = InBlossom[Base[v]] = true;
        u = Father[v];
        if(Base[u] != NewBase) Father[u] = v;
    }
}

void BloosomContract(int u, int v) {
    NewBase = FindCommonAncestor(u, v);
    memset(InBlossom, false, sizeof(InBlossom));
    ResetTrace(u);
    ResetTrace(v);
    if(Base[u] != NewBase) Father[u] = v;
    if(Base[v] != NewBase) Father[v] = u;
    for(int tu = 1; tu <= idx; tu++) {
        if(InBlossom[Base[tu]]) {
            Base[tu] = NewBase;
            if(!InQueue[tu]) Push(tu);
        }
    }
}

void FindAugmentingPath() {
    memset(InQueue, false, sizeof(InQueue));
    memset(Father, 0, sizeof Father);
    for(int i = 1; i <= idx; i++) Base[i] = i;
    Head = Tail = 1;
    Push(Start);
    Finish = 0;
    while(Head < Tail) {
        int u = Pop();
        for(int v = 1; v <= idx; v++) {

            if(Graph[u][v] && (Base[u] != Base[v]) && (Match[u] != v)) {

                if((v == Start) || ((Match[v] > 0) && Father[Match[v]] > 0)) {
                    BloosomContract(u, v);
                }
                else if(Father[v] == 0) {
                    Father[v] = u;
                    if(Match[v] > 0) Push(Match[v]);
                    else {
                        Finish = v;
                        return;
                    }
                }
            }
        }
    }
}

void AugmentPath() {
    int u, v, w;
    u = Finish;
    while(u > 0) {
        v = Father[u];
        w = Match[v];
        Match[v] = u;
        Match[u] = v;
        u = w;
    }
}

void Edmonds() {
    memset(Match, 0, sizeof Match);
    for(int u = 1; u <= idx; u++) {
        if(Match[u] == 0) {
            Start = u;
            FindAugmentingPath();
            if(Finish > 0) AugmentPath();
        }
    }
}

void PrintMatch() {
    Count = 0;
    for(int u = 1; u <= idx; u++) {
        if(Match[u] > 0) Count++;
    }
    if(Count == idx) puts("Yes");
    else puts("No");
}

void solve() {
    CreatGraph();
    Edmonds();
    PrintMatch();
}

int main() {
    freopen("in.txt", "r", stdin);
    while(~scanf("%d%d", &n, &m)) {
        init();
        for(int i = 1; i <= n; i++) {
            scanf("%d", &d[i]);
        }
        for(int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            e[u].push_back(v);
            e[v].push_back(u);
            edge[i] = {u, v};
        }
        solve();
    }
    return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值