2020牛客多校第一场By Rynar

A.B-Suffix Array

B.Infinite Tree

C.Domino

D.Quadratic Form

E.Counting Spanning Trees

F.Infinite String Comparision

Periodicity Lemma:对于S周期p,q,p+q-gcd(p,q)<=|S|,则|p-q|,gcd(p,q)也是周期
可得:>=a+b-gcd(a,b)就可以比较大小
证明Periodicity Lemma:
先证引理:对于S周期p,q,gcd(p,q)=1,p+q-1<=|S|,则gcd(p,q)也是周期
令p>q,p=kq+t,此处s下标从1开始p+q-1结束
i==p时,s[i]=s[t]=s[t+p](t+p=kq+t+t<p+q-1=kq+q+t)=s[2*t%p]=...
因为gcd(p,q)==1,必然搜到所有点
即s[1]=s[2]=...=s[p+q-1],则gcd(p,q)=1也为S的周期
因此引理得证
接下去证明,不妨令|S|=p+q-gcd(p,q)
把gcd(p,q)整段当成一个字母,可由上面引理得此时gcd(p,q)也为周期
当|S|>=p+q-gcd(p,q),易得gcd(p,q)也为周期

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char a[N],b[N];
int gcd(int x,int y){
    return x%y?gcd(y,x%y):y;
}
signed main(){
    while (scanf("%s%s",&a,&b)==2){
        int l1=strlen(a),l2=strlen(b);
        int g=l1+l2-gcd(l1,l2);
        for (int i=l1;i<g;i++)a[i]=a[i-l1];
        for (int i=l2;i<g;i++)b[i]=b[i-l2];
        a[g]=b[g]='\0';
        int p=strcmp(a,b);
        if (p==0)puts("=");
        else if (p>0)puts(">");
        else puts("<");
    }
    return 0;
}

G.BaXianGuoHai, GeXianShenTong

H.Minimum-cost Flow

题意:每条边的cost已经确定,所有边的流量相等却不确定,给出q(<1e6)组流量情况,用u/v(>1)表示,输出流出1流量所需要的cost a/b,若不能输出1流量,则输出NaN
思路:先增广费用流求出所有的增广路,并做前缀和,面对询问,直接利用前缀和位置输出cost or NaN

const int N=1001+10;
int n,m,k;
int Cost=0,Flow=0;
int vis[N],dis[N],head[N];
int step;
struct node{
    int to,cap,cost,n;
}e[N<<1];
void add(int x,int y,int v,int c){
    e[step].to=y;
    e[step].cap=v;
    e[step].cost=c;
    e[step].n=head[x];
    head[x]=step++;
}
bool spfa(int s,int t){
    for(int i=0;i<=n;i++) vis[i]=0,dis[i]=inf;//要改
    deque<int>q;
    q.push_back(t);
    dis[t]=0;
    vis[t]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop_front();
        for(int i=head[u];~i;i=e[i].n){
            int v=e[i].to;
            if(e[i^1].cap&&dis[v]>dis[u]+e[i^1].cost){
                dis[v]=dis[u]+e[i^1].cost;
                if(!vis[v]){
                    vis[v]=1;
                    if(!q.empty()&&dis[v]<dis[q.front()]){//SLF优化
                        q.push_front(v);
                    }
                    else q.push_back(v);
                }
            } 
        }
        vis[u]=0;
    } 
    return dis[s]<inf;
}
int dfs(int s,int t,int flow){
    vis[s]=1;
    if(s==t||flow<=0) return flow;
    int res,used=0;
    for(int i=head[s];~i;i=e[i].n){
        int v=e[i].to;
        if(!vis[v]&&e[i].cap&&dis[s]-dis[v]==e[i].cost){
            res=dfs(v,t,min(e[i].cap,flow-used));
            if(res) {
                e[i].cap-=res;
                e[i^1].cap+=res;
                Cost+=res*e[i].cost;
                used+=res;
            }
            if(used==flow)break;
        }
    }
    return used;
}
void zkw(int s,int t){
    while(spfa(s,t)){
        vis[t]=1;
        while(vis[t]){
            for(int i=0;i<=n;i++) vis[i]=0;//要改
            Flow+=dfs(s,t,inf);
        }
    }
}
ll gcd (ll x,ll y){
    return x%y?gcd(y,x%y):y;
}
int fl[N],co[N],sum[N];
int main(){
    int s,t,T;
    while (scanf("%d%d",&n,&m)==2){
        step=0;
        memset(head,-1,sizeof head);
        rep(i,1,m){
            int u,v,f;
            scanf("%d%d%d",&u,&v,&f);
            add(u,v,1,f);
            add(v,u,0,-f);
        }
        add(0,1,1,0);
        add(1,0,0,0);
        int cnt=0;
        for (int i=1;i<=101;i++){//增广所有的路
            Cost=0,Flow=0;
            e[step-1].cap=0;
            e[step-2].cap=1;
            zkw(0,n);
            if (Flow==0&&Cost==0){
                cnt=i-1;
                break;
            }
            fl[i]=Flow;co[i]=Cost;
        }
        sum[0]=0;
        for (int i=1;i<=cnt;i++)sum[i]=sum[i-1]+co[i];
        scanf("%d",&T);
        while (T--){
            scanf("%d%d",&s,&t);
            if (s==0){
                printf("NaN\n");
                continue;
            }
            ll cost=0,flow=t;
            if (t/s>cnt||(t/s==cnt&&t%s)){
                printf("NaN\n");
            }
            else{
                cost=1ll*sum[t/s]*s+(t-t/s*s)*co[t/s+1];
                ll g=gcd(cost,flow);
                printf("%lld/%lld\n",cost/g,flow/g);
            }
        }
    }
    return 0;
}

I.1 or 2

题意:n个点,m条边,取其中一定的边满足每个点的度都是的d[i],问能否满足
思路:一般图匹配,带花树算法,建图如下,每个点的点数为度数的个数

const int N=2333;
int n,m;
int cnt,match[N];//点数INIT
int fa[N];
vector<int>g[N];//INIT
int tp[N],pre[N];
queue<int>q;
int tim=0,tic[N];
void add(int u,int v){g[u].pb(v);g[v].pb(u);}
int ff(int x){if(x == fa[x]) return x; return fa[x]=ff(fa[x]);}
int lca(int x, int y){
    tim++;x=ff(x);y=ff(y);
    while(tic[x]!=tim){
        tic[x]=tim;
        x=ff(pre[match[x]]);
        if(y)swap(x, y);
    }
    return x;
}
void go(int u,int v,int p){
    while(ff(u)!=p){
        pre[u]=v;v=match[u];
        if(tp[v]==2) tp[v]=1,q.push(v);//
        if(ff(u)==u) fa[u]=p;
        if(ff(v)==v) fa[v]=p;
        u=pre[v];
    }
}
bool aug(int s){
    while(q.size()) q.pop(); q.push(s);
    fors(i, 0, N+1) fa[i] = i, pre[i] = tp[i] = 0;
    tp[s] = 1;
    while(q.size()){
        int u = q.front(); q.pop();
        for(int v: g[u]){
            if(tp[v] == 2||ff(u)==ff(v)) continue;
            if(!tp[v]){
                tp[v] = 2; pre[v] = u;
                if(!match[v]){//找到增广点,一路返回修改
                    int now = v, tmp;
                    while(now){
                        tmp = match[pre[now]];
                        match[pre[now]] = now; match[now] = pre[now];
                        now  = tmp;
                    }
                    return true;
                }
                tp[match[v]] = 1; q.push(match[v]);
            }else if(tp[v] == 1){
                int p = lca(u, v);
                go(u,v,p); go(v, u, p);
            }
        }
    }return false;
}
 
int d[N],sumd;
vector<int>to[N];
void init(){
    sumd=0;
    cnt=0;
    for (int i=1;i<=n;i++)to[i].clear();
    for (int i=1;i<=n;i++){
        scanf("%d",&d[i]), sumd+=d[i];
        for (int j=1;j<=d[i];j++) to[i].pb(++cnt),g[cnt].clear();
    }
    for (int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d", &u, &v);
        ++cnt; g[cnt].clear();
        for(int id: to[u]) add(id,cnt);
        ++cnt; g[cnt].clear(); add(cnt,cnt-1);
        for(int id: to[v]) add(id,cnt);
    }
}
bool solve(){
    int ans = 0;
    for (int i=1;i<=cnt;i++) match[i]=0;
    for (int i=1;i<=cnt;i++) ans+=(!match[i] && aug(i));
    return ans*2==cnt;
}
int main(){
    while(scanf("%d%d",&n,&m)==2){
        init();
        if(solve())puts("Yes");
        else puts("No");
    }
}

J.Easy Integration

\[\int_0^1 {(x-x^2)^n}\,{\rm d}x=\int_0^1 {x^n*(1-x)^n}\,{\rm d}x=(\frac{1}{n+1}{x^{n+1}*(1-x)^n}){|^0_1}+\frac{n}{n+1}\int_0^1 {x^{n+1}*(1-x)^{n-1}}\,{\rm d}x\\ =\frac{n}{n+1}\int_0^1 {x^{n+1}*(1-x)^{n-1}}\,{\rm d}x =\frac{n!}{(n+1)*(n+2)*...*(2*n)}\int_0^1{x^{2*n}}\,{\rm d}x=\frac{n!*n!}{(2*n+1)!}\]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+10;
const int mod=998244353;
int x[N];
int qpow(ll x,int y){
    int ans=1;
    while (y){
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;y>>=1;
    }
    return ans;
}
signed main(){
    x[1]=1;
    for (ll i=2;i<N;i++){
        x[i]=x[i-1]*i%mod;
    }
    int n;
    while (scanf("%d",&n)!=EOF){
        printf("%d\n",1ll*x[n]*x[n]%mod*qpow(x[2*n+1],mod-2)%mod);
    }
    return 0;
}
posted @ 2020-07-19 17:15  Rynar  阅读(200)  评论(0)    收藏  举报