2020牛客多校第一场反思+总结+题解(AFHIJ)

题目链接t_{i}

https://ac.nowcoder.com/acm/contest/5666#question

题解

A题B-Suffix Array

题意:给你一个字符串s,同时定义B函数为:B\left ( s_{1}s_{2}s_{3}...s_{n}\right )= t_{1}t_{2}t_{3}...t_{n} 其中t_{i}=min_{1\leqslant j< i,s_{j}=s_{i}} \left \{ i-j \right \},如果没有符合的j,那么t_{i}=0。然后让你求出s字符串的所有后缀串按照B函数求出的字符串t排序后的顺序。

这个题有两种做法,一种是直接套用官方题解给出的结论直接求后缀数组就行,一种是按照正常思路来解,但是相对而言还算好想(相比官方题解)。

先讲第二种解法,也是比赛时还能想到的。

首先我们如果能想到一种直接能比较两个后缀大小的方法,那这个题就好办了,直接排序就行了。

下面讲一下怎样比较两个后缀。

考虑一个字符串s按照b函数求出来的新字符串t的形式,一定是开头一个0,然后是一堆数字之后紧跟着一个0,再一堆数字

类似于这种:0x_{1}x_{2}...x_{n}0y_{1}y_{2}...y_{n},因此我们可以考虑先比较两个后缀的开头的连续相同字符个数,不妨定义一个数组dis[i]表示后缀从i开头的连续相同字符个数。

当两个后缀的dis数组不相同时,dis数组小的肯定在前面,eg:aaaab(01110)和aaaba(01102),这时aaaab肯定在aaaba前面。

当两个后缀的dis数组相同时,不妨假设一个后缀为aaabbbab(01101142),另一个后缀为bbbab(01102)。这种情况下我们可以考虑如果能够直接跨过前面0110的比较而直接比较1和2就方便了许多,假设第一个后缀为从i开始,第二个后缀为从j开始,可以得知[i,i+dis[i]]和[j,j+dis[j]]这个区间内的t字符数组都相等,即例子中的"011",而从i+dis[i]开始和j+dis[j]开始的t字符数组里,又有长度为lcp(i+dis[i],j+dis[j])的t字符数组也对应相等,因此我们就可以直接比较b[i+dis[i]+lcp]和b[j+dis[j]+lcp]了,值小的自然在前面。

当然还有两种特殊情况,当i+dis[i]>n时,eg:ba和a,这个时候ba直接放在前面就行了,而当j+dis[j]>n时,放在后面就行了(上一种情况的i和j调换过了的情况)。

时间复杂度:O(nlognlogn)

代码实现:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+7;
struct SA {
    int sa[N], ra[N], height[N];
    int t1[N], t2[N], c[N];
    void build(int *str, int n, int m) {
        str[n] = 0;
        n++;
        int i, j, p, *x = t1, *y = t2;
        for (i = 0; i < m; i++) c[i] = 0;
        for (i = 0; i < n; i++) c[x[i] = str[i]]++;
        for (i = 1; i < m; i++) c[i] += c[i - 1];
        for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
        for (j = 1; j <= n; j <<= 1) {
            p = 0;
            for (i = n - j; i < n; i++) y[p++] = i;
            for (i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
            for (i = 0; i < m; i++) c[i] = 0;
            for (i = 0; i < n; i++) c[x[y[i]]]++;
            for (i = 1; i < m; i++) c[i] += c[i - 1];
            for (i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
            swap(x, y);
            p = 1;
            x[sa[0]] = 0;
            for (i = 1; i < n; i++)
                x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j]) ? p - 1 : p++;
            if (p >= n) break;
            m = p;
        }
        n--;
        for (int i = 0; i <= n; i++) ra[sa[i]] = i;
        for (int i = 0, j = 0, k = 0; i <= n; i++) {
            if (k) k--;
            j = sa[ra[i] - 1];
            while (str[i + k] == str[j + k]) k++;
            height[ra[i]] = k;
        }
        st_init(height, n);
    }
    int lg[N], table[23][N];
    void st_init(int *arr, int n) {
        if (!lg[0]) {
            lg[0] = -1;
            for (int i = 1; i < N; i++)
                lg[i] = lg[i / 2] + 1;
        }
        for (int i = 1; i <= n; ++i)
            table[0][i] = arr[i];
        for (int i = 1; i <= lg[n]; ++i)
            for (int j = 1; j <= n; ++j)
                if (j + (1 << i) - 1 <= n)
                    table[i][j] = min(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
    }
    int lcp(int l, int r) {
        l = ra[l], r = ra[r];
        if (l > r) swap(l, r);
        ++l;
        int t = lg[r - l + 1];
        return min(table[t][l], table[t][r - (1 << t) + 1]);
    }
}sa;
string s;
int n;
int b[N],dis[N],res[N];
bool cmp(int i,int j){
    if(dis[i]!=dis[j]) return dis[i]<dis[j];
    if(i+dis[i]>n) return  true;
    if(j+dis[j]>n) return false;
    int lcp=sa.lcp(i+dis[i],j+dis[j]);
    // cout<<i+dis[i]<<" "<<j+dis[j]<<endl;
    // cout<<lcp<<endl;
    // cout<<i+dis[i]+lcp<<" "<<j+dis[j]+lcp<<endl;
    // cout<<b[i+dis[i]+lcp]<<" "<<b[j+dis[j]+lcp]<<endl;
    return b[i+dis[i]+lcp]<b[j+dis[j]+lcp];
}
int main(){
    while(cin>>n>>s){
        int pa=-1,pb=-1;
        for(int i=0;i<n;i++){
            if(s[i]=='a'){
                if(pa==-1) b[i]=0;
                else b[i]=i-pa;
                pa=i;
            }
            else{
                if(pb==-1) b[i]=0;
                else b[i]=i-pb;
                pb=i;
            }
        }
        pa=pb=-1;
        for(int i=n-1;i>=0;i--){
            if(s[i]=='a'){
                if(pb==-1) dis[i+1]=n-i;
                else dis[i+1]=pb-i;
                pa=i;
            }
            else{
                if(pa==-1) dis[i+1]=n-i;
                else dis[i+1]=pa-i;
                pb=i;
            }
        }
        // for(int i=0;i<n;i++) cout<<b[i]<<" ";
        // cout<<endl;
        // for(int i=1;i<=n;i++) cout<<dis[i]<<" ";
        // cout<<endl;
        for(int i=1;i<=n;i++) res[i]=i;
        sa.build(b,n,n+2);
        // cout<<cmp(1,7)<<endl;
        sort(res+1,res+1+n,cmp);
        for(int i=1;i<=n;i++) cout<<res[i]<<" ";
        cout<<endl;
    }
    return 0;
}
/*
14
aabaaabbabba
bbabba


3 9
2
5 11
1 3
1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 
*/

第二种做法(转自2020 牛客多校训练第一场之 A

定义c[i]的值是i后面离“i指针”对应的字母最近的与s[i]同字符的距离,b数组就与这个c数组的后缀数组。

可以把这个c数组给模拟出来,求出它的后缀(当一个字母后面没有和他相同的字母时,无穷大了,就设为数组长度n,最后一位没啥用,随便设一个比较大的数。避免冲突,就设成n+1)。
根据关系求出sa数组,把这个字符串翻转过来,去掉第一位就能模拟出结果了。

eg:设字符串为abaab,它的c数组为231556,列出c的后缀为: 231556,31556,1556,556,56,6。可以求得 sa:312456,反过来去掉首位的6,54213就是答案了。

代码实现:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
static const int N = 1e5+7;
string s;
int n;
struct CharRank
{
    int operator[](int i) const { return s[i]; }
    const int *s;
};
template <int N>
struct SA
{
    void compute(int _n, const int *s)
    {
        n = _n;
        sort(n, IdOrder{}, CharRank{s}, sa);
        int range = rank(CharRank{s}, CharRank{s});
        for (int length = 1; length < n && range < n; length <<= 1)
        {
            memcpy(trk, rk, sizeof(*rk) * n);
            TRank r1{n, length, trk}, r0{n, 0, trk};
            sort(range + 1, IdOrder{}, r1, tsa);
            sort(range + 1, TOrder{tsa}, r0, sa);
            range = rank(r0, r1);
        }
    }
 
    int sa[N], rk[N];
 
private:
    struct IdOrder
    {
        int operator[](int i) const { return i; }
    };
 
    struct TOrder
    {
        int operator[](int i) const { return sa[i]; }
        const int *sa;
    };
 
    struct TRank
    {
        int operator[](int i) const
        {
            return i + shift < n ? rk[i + shift] + 1 : 0;
        }
        int n, shift;
        const int *rk;
    };
 
    template <typename Order, typename Rank>
    void sort(int range, const Order &o, const Rank &r, int *out)
    {
        memset(count, 0, sizeof(*count) * range);
        for (int i = 0; i < n; ++i)
        {
            count[r[i]]++;
        }
        for (int i = 1; i < range; ++i)
        {
            count[i] += count[i - 1];
        }
        for (int i = n; i--;)
        {
            out[--count[r[o[i]]]] = o[i];
        }
    }
 
    template <typename Rank0, typename Rank1>
    int rank(const Rank0 &r0, const Rank1 &r1)
    {
        rk[sa[0]] = 0;
        for (int _ = 1; _ < n; ++_)
        {
            int i = sa[_];
            int j = sa[_ - 1];
            rk[i] = rk[j] + (r0[i] != r0[j] || r1[i] != r1[j]);
        }
        return rk[sa[n - 1]] + 1;
    }
 
    int n;
    int count[N], tsa[N], trk[N];
};
int c[N + 1];
SA<N + 1> sa;
int main()
{
    while (~scanf("%d", &n))
    {
        cin>>s;
        int pre1=n,pre2=n;
        for(int i=n-1;i>=0;i--){
            if(s[i]=='a'){
                if(pre1==n) c[i]=n-1;
                else c[i]=pre1-i-1;
                pre1=i;
            }
            else{
                if(pre2==n) c[i]=n-1;
                else c[i]=pre2-i-1;
                pre2=i;
            }
        }
        c[n]=n;
        // for (int i = 0; i <= n; i++)
        //     cout << c[i] << " ";
        // cout << endl;
        sa.compute(n+1,c);
        // for (int i = 0; i <= n; i++)
        //     cout << sa.sa[i] << " ";
        // cout << endl;
        for (int i = n-1; i>=1 ; i--)
        {
            printf("%d ", sa.sa[i] + 1);
        }
        printf("%d\n", sa.sa[0] + 1);
    }
    return 0;
}
/*
2
aa
3
aba
5
abaab
 
b 0
ab 00
aab 010
baab 0013
abaab 00213
0<00<0013<00213<010
 
aab ab abaab b baab
010 00 00213 0 0013
 
 
5
abaab
3 2 4 0 0 0
5 4 3 1 0 2
5 4 2 1 3
*/

F题Infinite String Comparision

签到题,不多说,直接上代码

#include<bits/stdc++.h>
using namespace std;
 
 
int main()
{
    ios::sync_with_stdio(0);
    string a,b;
    while(cin>>a>>b)
    {
        while(a.size()<1e5+10){
            a+=a;
        }
        while(b.size()<1e5+10){
            b+=b;
        }
        int i;
        for(i=0;i<1e5+10;i++){
            if(a[i]>b[i]){
                cout<<'>'<<endl;
                break;
            }
            else if(a[i]<b[i]){
                cout<<'<'<<endl;
                break;
            }
        }
        if(i==1e5+10){
            cout<<'='<<endl;
        }
    }
    return 0;
}

H题Minimum-cost Flow

题意:

给你n个点m条边的图,每条边都有一个单位代价w,以及容量,有q次询问,每次询问把每条边的容量都定为u/v,然后让你求出改变容量后跑流量为1时的最小费用。

题目给的q是最多为1e5,因此考虑每次重建图的做法肯定是不行的。

比较可行的做法是先按照容量为1跑出来最大流和最小费用,然后找出容量为1时和容量为u/v时的最小费用之间的关系。

首先已知一个定理:对于每条边容量相等的一条增广路径而言,费用是和容量成正比的。

因此我们可以先求出容量为1的最大流和费用,并且在存储下每条增广路上的费用。

这里我们设容量为1时跑出的最大流为MAX。

而当容量为u/v时,跑出的最大流为MAX*u/v,当MAX*u/v<1,即跑不出最大流为1的S到T的路径,输出NaN。

否则的话,我们把容量都设为u,那么求的就是最大流为v的费用。

因为我们之前已经预处理求出每条增广路径上的费用,并且存的时候已经保证是从小到大的了。

因此我们可以直接从前往后枚举费用,并把容量为1时的费用转换成容量为u时的费用,同时保证流的和不会超过v就行。

时间复杂度:O(E*q),因为增广路最多有100条。

代码实现:

#include <iostream>
#include <cstring>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <deque>
#include <bitset>
#include <algorithm>
using namespace std;
   
#define PI acos(-1.0)
#define LL long long
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define mp make_pair
#define IN freopen("in.txt", "r", stdin)
#define OUT freopen("out.txt", "wb", stdout)
#define scan(x) scanf("%d", &x)
#define scan2(x, y) scanf("%d%d", &x, &y)
#define scan3(x, y, z) scanf("%d%d%d", &x, &y, &z)
#define sqr(x) (x) * (x)
#define pr(x) cout << #x << " = " << x << endl
#define lc o << 1
#define rc o << 1 | 1
#define pl() cout << endl
//固定流量的最小费用流
const int MAXN = 100 + 5;
const LL INF = 0x3f3f3f3f3f3f3f3f;
struct Edge {
    int from, to;
    LL  cap,flow,cost;
};
struct MCMF {
    int s, t, n, m;
    LL d[MAXN], p[MAXN], inq[MAXN], a[MAXN];
    vector<int> G[MAXN];
    vector<Edge> edges;
    vector<int> ans;
    void init(int n) {
        this->n = n;
        for (int i = 0; i < n; i++) G[i].clear();
        edges.clear();
        ans.clear();
    }
    void addedge(int from, int to, LL cap, LL cost) {
        edges.push_back((Edge){from, to, cap, 0, cost});
        edges.push_back((Edge){to, from, 0, 0, -cost});
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }
    bool bellman_ford(int s, int t, LL &flow, LL &cost) {
        memset(inq, 0, sizeof(inq));
        for (int i = 0; i < n; i++) d[i] = INF;
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = 0;
            for (int i = 0; i < G[u].size(); i++) {
                Edge &e = edges[G[u][i]];
                if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if (!inq[e.to]) {
                        Q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }
        if (d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u] ^ 1].flow -= a[t];
            u = edges[p[u]].from;
        }
        ans.push_back(d[t] * a[t]);
        return true;
    }
    LL min_cost(int s, int t) {
        LL flow = 0, cost = 0;
        while (bellman_ford(s, t, flow, cost));
        return flow;
    }
}F;
int main() {
    int n, m;
    while(~scan2(n, m)){
        F.init(n);
        for (int i = 0; i < m; i++){
            int u,v,w;
            scan3(u,v,w);
            F.addedge(--u,--v,1,w);
        }
        int q;scan(q);
        int S = 0, T = n - 1;
        LL MAX=F.min_cost(S,T);
        while(q--){
            LL u,v;scanf("%lld%lld",&u,&v);
            if(MAX*u<v){
                printf("NaN\n");
                continue;
            }
            LL sum=0;
            LL ans=0;
            for(int c:F.ans){
                if(sum+u>v){
                    ans+=1ll*(v-sum)*c;
                    break;
                }
                ans+=1ll*u*c;
                sum+=u;
            }
            LL cc=__gcd(ans,v);
            printf("%lld/%lld\n",ans/cc,v/cc);
        }
    }
    return 0;
}

I题1 or 2

题意:给你一个无向图,让你判断能否选出一些边,使得每个点的度数为di(1<=di<=2)。

hdu3551的简单版本,详细题解请参考hdu3551

代码实现:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1050;
bool g[maxn][maxn],inque[maxn],inpath[maxn];
bool inhua[maxn];
int st,ed,newbase,ans,n;
int base[maxn],pre[maxn],match[maxn];
int head,tail,que[maxn]; 
int x[maxn],y[maxn],f[maxn],mp[maxn][maxn],ne,np;

void Push(int u)
{
    que[tail]=u;
    tail++;
    inque[u]=1;
}
int Pop()
{
    int res=que[head];
    head++;
    return res;
}

int lca(int u,int v)
{
    memset(inpath,0,sizeof(inpath));
    while(1)
    {
        u=base[u];
        inpath[u]=1;
        if(u==st) break;
        u=pre[match[u]];    
    }    
    while(1)
    {
        v=base[v];
        if(inpath[v]) break;
        v=pre[match[v]];
    }
    return v;
} 
void reset(int u)
{
    int v;
    while(base[u]!=newbase)
    {
        v=match[u];
        inhua[base[u]]=inhua[base[v]]=1;
        u=pre[v];
        if(base[u]!=newbase) pre[u]=v;
    }
} 
void contract(int u,int v)//
{
    newbase=lca(u,v);
    memset(inhua,0,sizeof(inhua));
    reset(u);
    reset(v);
    if(base[u]!=newbase) pre[u]=v;
    if(base[v]!=newbase) pre[v]=u;
    for(int i=1;i<=n;i++)
    {
        if(inhua[base[i]]){
            base[i]=newbase;
            if(!inque[i])
                Push(i);
        }
    }
}
void findaug()
{
    memset(inque,0,sizeof(inque));
    memset(pre,0,sizeof(pre));
    for(int i=1;i<=n;i++)
        base[i]=i;
    head=tail=1;
    Push(st);
    ed=0;
    while(head<tail)
    {
        int u=Pop();
        for(int v=1;v<=n;v++)
        {
            if(g[u][v]&&(base[u]!=base[v])&&match[u]!=v)
            {
                if(v==st||(match[v]>0)&&pre[match[v]]>0)
                    contract(u,v);
                else if(pre[v]==0)
                {
                    pre[v]=u;
                    if(match[v]>0)
                        Push(match[v]);
                    else 
                    {
                        ed=v;
                        return ;    
                    }    
                }
            }
        }
    }
}
void aug()
{
    int u,v,w;
    u=ed;
    while(u>0)
    {
        v=pre[u];
        w=match[v];
        match[v]=u;
        match[u]=v;
        u=w;
    }
}
void edmonds()
{
    memset(match,0,sizeof(match));
    for(int u=1;u<=n;u++)
    {
        if(match[u]==0)
        {
            st=u;
            findaug();
            if(ed>0) aug();
        }
    }
}
void create()
{
    n=0;
    memset(g,0,sizeof(g));
    for(int i=1;i<=np;i++)
        for(int j=1;j<=f[i];j++)
            mp[i][j]=++n;
    for(int i=0;i<ne;i++)
    { 
        for(int j=1;j<=f[x[i]];j++)
            g[mp[x[i]][j]][n+1]=g[n+1][mp[x[i]][j]]=1;
        for(int j=1;j<=f[y[i]];j++)
            g[mp[y[i]][j]][n+2]=g[n+2][mp[y[i]][j]]=1;
        g[n+1][n+2]=g[n+2][n+1]=1; 
        n+=2;
    }    
}
void print()
{
    ans=0;
    for(int i=1;i<=n;i++)
        if(match[i]!=0)
            ans++;
    if(ans==n)    printf("Yes\n");
    else    printf("No\n");
}
int main()
{
    int t,k=0;
    while(~scanf("%d%d",&np,&ne))
    {
        for(int i=1;i<=np;i++)
            scanf("%d",&f[i]);
        for(int i=0;i<ne;i++)
            scanf("%d%d",&x[i],&y[i]);
        create();
        edmonds();
        print();    
    }     
    return 0;
}
/*
3 2
1 1 1
1 3
2 3
No
3 3
1 1 1
1 3
2 3
1 2
1 1 1


1 1 1 1
1+1=2
*/

J题Easy Integration

题意:给你一个数n,让你求出\int_{0}^{1}(x-x^{2})^{n}dx的值。

打表发现分子都是1,分母分别为6,30,140,630.....。oeis找规律发现分母的公式为\frac{(2n+1)!}{n!*n!}

官方题解给的是这是Wallis' integrals。详细证明参考https://en.wikipedia.org/wiki/Wallis%27_integrals

代码实现:

#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn = 2000005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
const double E = 2.718281828;
 
inline int read() {
    int x(0), f(1); char ch(getchar());
    while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
 
struct poi {
 
};
 
int n;
LL ji[maxn];
LL in[maxn];
map<int, LL> mp;
 
inline LL quickPow(LL x, LL n, LL mod) {
    LL ans = 1;
    while(n) {
        if(n & 1) ans *= x, ans %= mod;
        x *= x, x %= mod;
        n >>= 1;
    }
    return ans;
}
 
// inline LL inv(LL x) {
//     return quickPow(x, mod - 2, mod);
// }
 
//x->a关于b的逆元
//y->b关于a的逆元
inline void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
      if (!b) {d = a, x = 1, y = 0;}
      else{
          ex_gcd(b, a % b, y, x, d);
          y -= x * (a / b);
      }
  }
inline LL inv(LL t){//如果不存在,返回-1
     LL d, x, y;
     ex_gcd(t, mod, x, y, d);
     return d == 1 ? (x % mod + mod) % mod : -1;
 }
 
inline LL C(int n, int m) {
    LL ans = ji[n];
    if(ji[m] < maxn) ans *= in[ji[m]];
    else ans *= inv(ji[m]);
    ans %= mod;
    if(ji[n - m] < maxn) ans *= in[ji[n - m]];
    else ans *= inv(ji[n - m]);
    return ans % mod;
    // return ji[n] * inv(ji[m]) % mod * inv(ji[n - m]) % mod;
}
 
inline void sol() {
    if(mp.count(n)) {
        // printf("%lld\n",  mp[n]);
        cout << mp[n] << "\n";
        return;
    }
    LL ans = 0;
    _for(i, n + 1) {
        ans += C(n, i) * (mod + (i & 1 ? -1 : 1) * in[n + i + 1]) % mod; ans %= mod;
        // ans += mod + ji[n] * inv(ji[i]) % mod * inv(ji[n - i + 1]) % mod * ((i & 1) ? -1 : 1); ans %= mod;
    }
    cout << ans << "\n";
    mp[n] = ans;
}
 
int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    ji[0] = 1;
    _rep(i, 1, maxn - 1) ji[i] = ji[i - 1] * i, ji[i] %= mod;
    _rep(i, 1, maxn - 1) in[i] = inv(i);
    while(cin>>n) {
        LL up=ji[2*n+1]%mod;
        LL down=ji[n]%mod*ji[n]%mod;
        LL ans=up*quickPow(down,mod-2,mod)%mod;
        cout<<quickPow(ans,mod-2,mod)<<endl;
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值