zoukankan      html  css  js  c++  java
  • HDU校赛 | 2019 Multi-University Training Contest 2

    2019 Multi-University Training Contest 2

    http://acm.hdu.edu.cn/contests/contest_show.php?cid=849

    1005. Everything Is Generated In Equal Probability

    考虑一个随机的排列的逆序对个数,显然对于两个数(a,b),他们位置是均匀排布的,也就是说有(frac{1}{2})的概率成为逆序对,并且是独立的。

    所以一个长度为(n)的随机排列期望逆序对个数为(dfrac{inom{n}{2}}{2})

    我们考虑(dp),设(f_i)表示长度为(i)随机排列扔到给出的函数里的期望输出。

    那么直接照着函数转移:

    [f_i=frac{inom{n}{2}}{2}+frac{1}{2^n}sum_{j=0}^{i}inom{i}{j}f_j ]

    暴力转移,(O(1))回答就好了。

    复杂度(O(n^2+q))

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 998244353;
    
    int f[maxn],fac[maxn],ifac[maxn],n;
    
    int qpow(int a,int x) {
        int res=1;
        for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
        return res;
    }
    
    int c(int a,int b) {return 1ll*fac[a]*ifac[b]%mod*ifac[a-b]%mod;}
    
    int main() {
        fac[0]=ifac[0]=1;
        for(int i=1;i<=3000;i++) fac[i]=1ll*fac[i-1]*i%mod,ifac[i]=1ll*ifac[i-1]*qpow(i,mod-2)%mod;
        for(int i=2;i<=3000;i++) {
            for(int j=2;j<=i-1;j++) f[i]=(f[i]+1ll*f[j]*c(i,j)%mod)%mod;
            f[i]=1ll*f[i]*qpow(qpow(2,i),mod-2)%mod;
            f[i]=(f[i]+1ll*c(i,2)*qpow(2,mod-2)%mod)%mod;
            f[i]=1ll*f[i]*qpow(1-qpow(qpow(2,i),mod-2)+mod,mod-2)%mod;
        }
        for(int i=1;i<=3000;i++) f[i]=(f[i-1]+f[i])%mod;
        while(scanf("%d",&n)!=EOF) write(1ll*f[n]*qpow(n,mod-2)%mod);
        return 0;
    }
    

    1006. Fantastic Magic Cube

    首先考虑对于每个单位立方体开一个点,所有联通的立方体用一条边连起来,边权为点权之积。

    那么切开一个大立方体相当于断掉一些变,取边权。

    显然无论如何切答案都是一样的。

    那么直接统计答案就好了,设(N=n^3,a_i)表示点权:

    [ans=sum_{i=1}^{N}sum_{j=i+1}^{N}a_ia_j=dfrac{(sum_{i=1}^{N}a_i)^2-sum_{i=1}^{N}a_i^2}{2} ]

    那么用(fwt)求出每个权值出现了多少次,暴力算答案就好了。

    复杂度(O(nlog n))

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 2e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 998244353;
    const int inv2 = 499122177;
    
    int f[maxn],n,N;
    
    void fwt(int *r,int op) {
        for(int i=1;i<N;i<<=1)
            for(int j=0;j<N;j+=i<<1)
                for(int k=0;k<i;k++) {
                    int x=r[j+k],y=r[i+j+k];
                    r[j+k]=(x+y)%mod,r[i+j+k]=(x-y+mod)%mod;
                    if(op==-1) r[j+k]=1ll*r[j+k]*inv2%mod,r[i+j+k]=1ll*r[i+j+k]*inv2%mod;
                }
    }
    
    void solve() {
        for(N=1;N<=n;N<<=1);
        for(int i=0;i<n;i++) f[i]=1;
        for(int i=n;i<N;i++) f[i]=0;
        fwt(f,1);
        for(int i=0;i<N;i++) f[i]=1ll*f[i]*f[i]%mod*f[i]%mod;
        fwt(f,-1);int ans=0,tmp=0;
        for(int i=1;i<N;i++)
            ans=(ans+1ll*i*f[i]%mod)%mod,tmp=(tmp+1ll*i*i%mod*f[i]%mod)%mod;
        ans=1ll*ans*ans%mod;ans=(ans-tmp+mod)%mod;
        write(1ll*ans*inv2%mod);
    }
    
    int main() {
        while(scanf("%d",&n)!=EOF) solve();
        return 0;
    }
    

    1008. Harmonious Army

    二元组建图模板题。。。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 500+10;
    const int inf = 1e18;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    int head[maxn],tot=1,s,t,n,m,r[maxn][maxn],ans;
    struct edge{int to,nxt,w;}e[maxn*maxn];
    
    void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
    void ins(int u,int v,int w) {add(u,v,w),add(v,u,0);}
    
    int dis[maxn];
    
    int bfs() {
        memset(dis,-1,sizeof dis);
        queue<int > q;q.push(s);dis[s]=0;
        while(!q.empty()) {
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].nxt)
                if(e[i].w>0&&dis[e[i].to]==-1) {
                    dis[e[i].to]=dis[x]+1;
                    if(e[i].to==t) return 1;
                    q.push(e[i].to);
                }
        }return 0;
    }
    
    int dfs(int x,int flow) {
        if(x==t) return flow;
        int used=0;
        for(int v,i=head[x];i;i=e[i].nxt)
            if(dis[v=e[i].to]==dis[x]+1&&e[i].w>0) {
                int d=dfs(e[i].to,min(e[i].w,flow));
                e[i].w-=d,e[i^1].w+=d,used+=d,flow-=d;
                if(!flow) break;
            }
        if(!used) dis[x]=-1;
        return used;
    }
    
    int dinic() {int res=0;while(bfs()) res+=dfs(s,inf);return res;}
    
    void solve() {
        s=n+1,t=n+2;
        for(int i=1;i<=m;i++) {
            int u,v,a,b,c;read(u),read(v),read(a),read(b),read(c);
            ans-=(a+c)*2;
            r[s][u]+=c,r[s][v]+=c,r[v][t]+=a,r[u][t]+=a;
            r[u][v]+=a+c-b*2,r[v][u]+=a+c-b*2;
        }
        for(int i=1;i<=t;i++)
            for(int j=1;j<=t;j++)
                if(r[i][j]) ins(i,j,r[i][j]);
        write((-dinic()-ans)/2);
    }
    
    void clear() {
        tot=1;ans=0;
        memset(head,0,sizeof head);
        memset(r,0,sizeof r);
    }
    
    signed main() {
        while(scanf("%lld%lld",&n,&m)!=EOF) solve(),clear();
        return 0;
    }
    

    1010. Just Skip The Problem

    注意到最优一定是一位一位地问有没有,所以方案数直接就是阶乘。

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e6+3;
    
    int fac[maxn],n;
    
    int main() {
        fac[0]=1;
        for(int i=1;i<mod;i++) fac[i]=1ll*fac[i-1]*i%mod;
        while(scanf("%d",&n)!=EOF) write(n==2?2:(n>=mod?0:fac[n]));
        return 0;
    }
    

    1011. Keen On Everything But Triangle

    拿主席树维护区间,暴力判断就好了。

    因为最劣的情况是构成斐波那契数列,而斐波那契增长是指数级的,所以最多在主席树上询问(O(log v))次,(v)是值域。

    复杂度(O(Tnlog nlog v))

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    const int maxn = 2e5+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    const int N = 1e9;
    
    int n,q,rt[maxn];
    
    struct persistance_segment_tree {
        int ls[maxn*40],rs[maxn*40],s[maxn*40],seg;
    
        void insert(int &p,int pre,int l,int r,int x) {
            p=++seg;ls[p]=ls[pre],rs[p]=rs[pre],s[p]=s[pre]+1;
            if(l==r) return ;int mid=(l+r)>>1;
            if(x<=mid) insert(ls[p],ls[pre],l,mid,x);
            else insert(rs[p],rs[pre],mid+1,r,x);
        }
    
        int query(int a,int b,int l,int r,int k) {
            if(l==r) return l;int mid=(l+r)>>1;
            if(s[rs[b]]-s[rs[a]]>=k) return query(rs[a],rs[b],mid+1,r,k);
            else return query(ls[a],ls[b],l,mid,k-(s[rs[b]]-s[rs[a]]));
        }
    
        void clear() {
            for(int i=1;i<=seg;i++) ls[i]=rs[i]=s[i]=0;
            seg=0;
        }
    }T;
    
    int find(int l,int r,int x) {return T.query(rt[l-1],rt[r],1,N,x);}
    
    #define ll long long 
    
    void solve() {
        for(int i=1,x;i<=n;i++) read(x),T.insert(rt[i],rt[i-1],1,N,x);
        for(int i=1;i<=q;i++) {
            int l,r;read(l),read(r);
            if(r-l+1<3) {puts("-1");continue;}
            int a=find(l,r,1),b=find(l,r,2),c=find(l,r,3),x=3,bo=0;
            while(1) {
                if(a<b+c) {bo=1;printf("%lld
    ",1ll*a+b+c);break;}
                if(x==r-l+1) break;
                a=b,b=c,c=find(l,r,++x);
            }if(!bo) puts("-1");
        }
    }
    
    void clear() {
        T.clear();
        for(int i=1;i<=n;i++) rt[i]=0;
    }
    
    int main() {
        while(scanf("%d%d",&n,&q)!=EOF) solve(),clear();
        return 0;
    }
    

    1012. Longest Subarray

    考虑排除不合法的情况,在剩下的情况取最大值。

    那么对于每种颜色假设数量是(x),那么我们可以得到(O(x))个形如当(l)(asim b)之间时,(r)不能取(csim d​)的限制条件。

    显然这可以转化成一个矩形。

    那么直接扫描线就好了,复杂度(O(Tnlog n))

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    
    #define pii pair<int,int >
    #define vec vector<int >
    
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
    
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
    
    #define iter vector<int > :: iterator
    
    const int maxn = 1e5+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    int n,c,k,cnt;
    vector<int > p[maxn];
    
    struct l {int x,l,r,v;}r[maxn<<3];
    
    void add(int x1,int x2,int y1,int y2) {
        if(x1>x2||y1>y2) return ;
        r[++cnt]=(l){x1,y1,y2,1};
        r[++cnt]=(l){x2+1,y1,y2,-1};
    }
    
    int cmp(l x,l y) {return x.x<y.x;}
    
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    
    struct Segment_Tree {
        int mr[maxn<<2],tag[maxn<<2];
    
        void build(int p,int l,int r) {
            mr[p]=r;tag[p]=0;
            if(l==r) return ;
            build(ls,l,mid),build(rs,mid+1,r);
        }
    
        void update(int p,int l,int r) {
            if(tag[p]) mr[p]=-1;
            else if(mr[rs]!=-1) mr[p]=mr[rs];
            else mr[p]=mr[ls];
        }
    
        void cover(int p,int l,int r,int x,int y,int v) {
            if(x<=l&&r<=y) {
                tag[p]+=v;
                if(l==r) mr[p]=tag[p]?-1:r;
                else update(p,l,r);
                return ;
            }
            if(x<=mid) cover(ls,l,mid,x,y,v);
            if(y>mid) cover(rs,mid+1,r,x,y,v);
            update(p,l,r);
        }
    }T;
    
    void solve() {
        T.build(1,1,n);cnt=0;
        for(int i=1;i<=c;i++) p[i].clear();
        for(int i=1,x;i<=n;i++) read(x),p[x].pb(i);
        for(int i=1;i<=c;i++) 
            if(p[i].size()<k) {
                for(iter x=p[i].begin();x!=p[i].end();x++)
                    add(1,*x,*x,n);
            } else {
                int sz=p[i].size();
                add(1,p[i][0],p[i][0],p[i][k-1]-1);
                for(int x=0;x<sz-1;x++) add(p[i][x]+1,p[i][x+1],p[i][x+1],x+k>=sz-1?n:p[i][x+k+1]-1);
            }
        sort(r+1,r+cnt+1,cmp);int t=1,ans=0;
        for(int i=1;i<=n;i++) {
            while(r[t].x==i) T.cover(1,1,n,r[t].l,r[t].r,r[t].v),t++;
            if(T.mr[1]<=i) continue;
            ans=max(ans,T.mr[1]-i+1);
        }write(ans);
    }
    
    int main() {
        while(scanf("%d%d%d",&n,&c,&k)!=EOF) solve();
        return 0;
    }
    
  • 相关阅读:
    QDUOJ LC的课后辅导 单调递增栈
    蓝桥杯 时间问题
    区间sum 和为k的连续区间-前缀和
    康托展开-全排列的编码与解码
    康托展开-全排列应用
    背包之01背包、完全背包、多重背包详解
    HDU
    辗转相除求最大公约数与最小公倍数
    快速幂(反复平方法)
    HDU
  • 原文地址:https://www.cnblogs.com/hbyer/p/11270962.html
Copyright © 2011-2022 走看看