• 20190810


    AGC014 E Blue and Red Tree

    link

    $solution:$

    考虑题目的性质,可以发现蓝树与红树肯定有交,且必在最后一次割掉。

    所以考虑反向过程,如何从红树变为蓝树。

    将最后一次的情况往外推广,每一次也要有类似的交集,。

    考虑如何去维护,通过启发式合并 $set$ 与并查集,时间复杂度 $O(nlog^2 n)$ 。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=200001;
    map<pair<int,int> ,int> M;
    set<int> s[MAXN];
    queue<pair<int,int> > que;
    void add(int u,int v){
        s[u].insert(v),s[v].insert(u);
        if(u>v) swap(u,v);
        M[make_pair(u,v)]++;
        if(M[make_pair(u,v)]==2) que.push(make_pair(u,v));
        return; 
    }
    void del(int u,int v){
        s[u].erase(v),s[v].erase(u);
        if(u>v) swap(u,v);
        M.erase(make_pair(u,v));
    }
    set<int>::iterator it,it1;
    int n,f[MAXN];
    int find(int x){if(f[x]==x) return x;return f[x]=find(f[x]);}
    bool solve(){
        int tot=0;
        for(int i=1;i<=n;i++) f[i]=i;
        while(!que.empty()){
            int u=que.front().first,v=que.front().second;que.pop();
            tot++;
            u=find(u),v=find(v);
            if(s[u].size()<s[v].size()) swap(u,v);
            del(u,v);
            f[v]=u;
            for(it=s[v].begin();it!=s[v].end();){
                it1=it;it++;
                int end=*it1;end=find(end);
                del(v,end),add(u,end);
            }
        }
        return tot==(n-1);
    }
    int main(){
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
        n=read();
        for(int i=1;i<n;i++) add(read(),read());
        for(int i=1;i<n;i++) add(read(),read());
        if(solve()){printf("YES
    ");return 0;}
        printf("NO
    ");return 0;
    }
    View Code

    [2017集训队作业自选题#119] 众数MAX

    $solution:$

    众数肯定是要枚举的,考虑暴力求出对于众数 $x$ 的个数。

    设 $A_i$ 表示 $a_x=i$ 的出现次数,$B_i$ 亦如此。

    则 $Ans_i=sum min{A_j,B_{i-j}}$ 。这个式子很像能卷积的式子,但是无法计算 $min$ 操作。

    但是可以将式子拆开去做,则 $$Ans_i=sum_{x=1}^{n(k)} sum_{j=0}^i [A_jgeq x] imes [B_{i-j}geq x]\=sum_{x=1}^nsum_{j=0}^i c_j imes d_{i-j}$$

    时间复杂度 $O(k imes nlog n)$ 。

    但是此刻 $k$ 与 $n$ 同阶。通过简单思考发现对于 $A$ 中出现 $k$ 次的不超过 $dfrac{n}{k}$ 个,所以可以通过设置 $k$,$NTT$ 与暴力同时处理两种不同情况。

    时间复杂度 $O(k imes nlog n+dfrac{n^2}{k^2})$ ,在 $k$ 取 $10$ 时应为最优。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define int long long
    #define mod 998244353
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=600001;
    namespace Poly{
        int f[MAXN],g[MAXN],flip[MAXN];
        inline int ksm(int a,int b){
            int ans=1;
            while(b){
                if(b&1) ans*=a,ans%=mod;
                a*=a,a%=mod;
                b>>=1;
            }return ans;
        }
        inline int Get(int lim){
            int len=1;while(len<=lim) len<<=1;
            for(register int i=0;i<len;i++) flip[i]=((flip[i>>1]>>1)|(i&1?len>>1:0));
            return len;
        }
        inline void NTT(int *f,int lim,int opt){
            for(register int i=0;i<lim;i++) if(i<flip[i]) swap(f[i],f[flip[i]]);
            for(register int p=2;p<=lim;p<<=1){
                int len=p>>1,buf=ksm(3,(mod-1)/p);
                if(opt==-1) buf=ksm(buf,mod-2);
                for(register int be=0;be<lim;be+=p){
                    int tmp=1;
                    for(register int l=be;l<be+len;l++){
                        int t=f[l+len]*tmp;t%=mod;
                        f[l+len]=(f[l]-t+mod)%mod,f[l]=(f[l]+t)%mod;
                        tmp*=buf,tmp%=mod;
                    }
                }
            }
            if(opt==-1){
                int Inv=ksm(lim,mod-2);
                for(register int i=0;i<lim;i++) f[i]*=Inv,f[i]%=mod;
            }return;
        }
    }
    int n,Maxn,a[MAXN],b[MAXN],A[MAXN],B[MAXN],f[MAXN],g[MAXN],ans[MAXN],staa[MAXN],stab[MAXN];
    signed main(){
        freopen("max.in","r",stdin);
        freopen("max.out","w",stdout); 
        n=read();
        for(int i=1;i<=n;i++) a[i]=read(),A[a[i]]++;
        for(int i=1;i<=n;i++) b[i]=read(),B[b[i]]++;
        int lim=Poly::Get(200000);
        for(register int i=1;i<=10;i++){
            memset(f,0,sizeof(f)),memset(g,0,sizeof(g));
            for(register int j=1;j<=100000;j++) f[j]=(A[j]>=i),g[j]=(B[j]>=i);
            Poly::NTT(f,lim,1),Poly::NTT(g,lim,1);
            for(register int j=0;j<lim;j++) f[j]*=g[j],f[j]%=mod;
            Poly::NTT(f,lim,-1);
            for(int j=0;j<lim;j++) ans[j]+=f[j];
        }
        for(register int i=1;i<=100000;i++){
            if(A[i]>10) staa[++staa[0]]=i;
            if(B[i]>10) stab[++stab[0]]=i;
        }
        for(register int i=1;i<=staa[0];i++)
            for(int j=1;j<=stab[0];j++) ans[staa[i]+stab[j]]+=min(A[staa[i]],B[stab[j]])-10;
        for(register int i=1;i<=200000;i++) Maxn=max(Maxn,ans[i]);
        printf("%lld
    ",Maxn);return 0;
    }
    View Code

     AGC005 D ~K Perm Counting

    link

    $solution:$

    考虑容斥原理,设 $g_i$ 表示至少有 $i$ 个点满足 $|a_j-j|=k$ 的方案数。

    则 $Ans=sum_i (-1)^i imes g_i imes (n-i)!$ 。

    考虑建立二分图,左为下标,右为权值,若有边 $(u,v)$ ,则下标为 $u$ 不能选 $v$ 。

    将二分图拉出来简单 $dp$ 即可。

    时间复杂度 $O(n^2)$ 。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define int long long
    #define mod 924844033
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=4001;
    int fac[MAXN],f[MAXN][MAXN][2],n,k,sta[MAXN],col[MAXN];
    int Mod(int x){return ((x%mod)+mod)%mod;}
    signed main(){
        freopen("count.in","r",stdin);
        freopen("count.out","w",stdout);
        n=read(),k=read();fac[0]=1;
        for(int i=1;i<=n;i++) fac[i]=(fac[i-1]*i)%mod;
        for(int i=1;i<=k;i++){
            col[0]++;
            for(int j=i;j<=n;j+=k) sta[++sta[0]]=j,col[sta[0]]=col[0];
            col[0]++;
            for(int j=i;j<=n;j+=k) sta[++sta[0]]=j,col[sta[0]]=col[0]; 
        }
        f[1][0][0]=1;
        for(int i=2;i<=sta[0];i++){
            for(int j=0;j<=n;j++){
                f[i][j][0]=f[i-1][j][0]+f[i-1][j][1];f[i][j][0]=Mod(f[i][j][0]);
                if(j!=0&&col[i]==col[i-1]) f[i][j][1]=f[i-1][j-1][0],f[i][j][1]%=mod;
            }
        }
        int Ans=0,pw=1;
        for(int i=0;i<=n;i++){
            Ans+=pw*fac[n-i]*((f[sta[0]][i][0]+f[sta[0]][i][1])%mod),Ans=Mod(Ans),pw*=-1;
        }
        printf("%lld
    ",Ans);return 0;
    }
    View Code
  • 相关阅读:
    oracle12.2RAC之OGG安装配置(一)
    【java框架】JPA(3) -- JPA映射关系
    【java框架】JPA(2) -- JPA基础
    【java框架】Struts2(3) -- Struts2结果视图及参数接收
    【问题管理】-- Struts2配置struts.xml中Action访问报There is no Action mapped for namespace...
    【java框架】Struts2(2) -- Struts2配置
    JavaScript(1) -- JS入门
    【java框架】MyBatis(2)--Mapper代理接口及批量操作
    【java框架】MyBatis(1)--MyBatis入门
    C# AutoMapper 了解一下
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/11332482.html
Copyright © 2020-2023  润新知