• noip模拟赛Bywzj52501 17.10.18


    T1 rob

    环形消灭虫子

    先想出了一个n^2暴力

    然后我们想到 如果从两个连续的点求解 则会出现仅有的两种结果

    (因为这两种情况的交是全集)

    当时因为Naive求了50次

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #define ll long long
    using namespace std;
    int a[2*152600];
    ll dp[2*152600];
    int main()
    {
        freopen("rob.in","r",stdin);
        freopen("rob.out","w",stdout);
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i+n]=a[i];}
        ll res=-1;
        int tms=min(n,50);
        for(int i=0;i<tms;i++)
        {
            memset(dp,0,sizeof(dp));
            for(int j=1;j<=n;j++)
            {
                if(j>2)dp[j]=dp[j-2];
                if(j>=3 && dp[j]<dp[j-3])dp[j]=dp[j-3];
                dp[j]+=a[j+i];
            }
            dp[n]=max(dp[n-1],dp[n-2]);
            res=max(res,dp[n]);
        }
        printf("%lld",res);
        return 0;
    }
    View Code

    T2 destroy

    有n个点m条边

    现在删掉一些边 把图分为两个联通块 求两个联通块中权值之和最小值

    我们跑一个最小生成树 再把其中最大的一条边砍掉 就可以保证 剩下的是两个联通块 且权值之和最小

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #define ll long long
    using namespace std;
    inline int read()
    {
        char ch=getchar();
        int x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m;
    struct edg
    {
        int from,to;
        ll val;
        bool operator <(const edg b)const
        {
            return val<b.val;
        }
    }es[152600];
    int cnt;
    int fa[152600];
    inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    
    inline void add(int u,int v,int w)
    {
        es[cnt++]=(edg){u,v,w};
    }
    ll mx,sm;
    void kruskal()
    {
        sort(es,es+cnt);
        for(int i=0;i<=cnt;i++)fa[i]=i;
        for(int i=0;i<cnt;i++)
        {
            int fx=find(es[i].from);
            int fy=find(es[i].to);
            if(fx!=fy)
            {
                mx=max(mx,es[i].val);
                sm+=es[i].val;
                fa[fx]=fy;
            }
        }
    }
    
    int main()
    {
        freopen("destroy.in","r",stdin);
        freopen("destroy.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        kruskal();
        printf("%lld",sm-mx);
        return 0;
    }
    View Code

    T3 permutation

    给定n个数 求这n个数全排列中满足

    对所有 2 ≤ i ≤ N - 1,都有 A[i - 1] + A[i + 1] ≥ 2 × A[i]

    的方案数

    50分 全排列

    70分 状压 n^3*2^n

    100分 爆搜

    爆搜。。。

    但是LZJ巨神告诉我们 事情并没有这么简单

    首先  满足条件的序列肯定是下凸的单峰型

    首先考虑序列

    i  j  ... ...  l  k

    现在要在这个序列左端插入一个x 只要满足 a[x]-a[j]>=2*a[i]就可以插进来 j l之间是什么数并不影响结果

    右端插x同理

    于是我们排序 枚举每个数往左插还是往右插

    复杂度n^5

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #define ll long long
    const int MOD=998244353;
    using namespace std;
    inline int read()
    {
        char ch=getchar();
        int x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
        return x*f;
    }
    int a[50];
    int n;
    ll ans;
    int dp[50][50][50][50];
    bool vis[50][50][50][50];
    int cnt[50];
    void dfs(int i,int j,int k,int l)
    {
        if(vis[i][j][k][l])return;
        vis[i][j][k][l]=1;
        int mx=max(i,max(j,max(k,l)));
        mx++;
        if(mx==n)
        {
               if((!j||a[j]-a[i]>=a[i]-a[mx]) && (!l||a[l]-a[k]>=a[k]-a[mx]))  (ans+=dp[i][j][k][l])%=MOD;
               return;
        }
        for(int o=0;o<=cnt[mx];o++)
        {
            bool flag1=0,flag2=0;
            if(!j||a[mx]+a[j]>=2*a[i]||!o)flag1=1;
            if(!l||a[mx]+a[l]>=2*a[k]||!(cnt[mx]-o))flag2=1;
            if(flag1 && flag2)
            {
                   int ni=i,nj=j,nk=k,nl=l;
                   if(o==1)nj=i,ni=mx;
                   else if(o>1)nj=ni=mx;
                   if(cnt[mx]-o==1)nl=k,nk=mx;
                   else if(cnt[mx]-o>1)nl=nk=mx;
                   (dp[ni][nj][nk][nl]+=dp[i][j][k][l])%=MOD;
              }
        }
    }
    
    int main()
    {
        //freopen("permutation.in","r",stdin);
        //freopen("permutation.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)a[i]=-read();
        sort(a+1,a+n+1);
        int tag=0;
        for(int i=1;i<=n;i++)a[i]=-a[i];
        for(int i=1;i<=n;i++)
        {
               if(a[i]==a[tag])cnt[tag]++;
               else
               {
                   a[++tag]=a[i];
                   cnt[tag]=1;
            }
        }
        n=tag;
        dp[0][0][0][0]=1;
        for(int i=0;i<n;i++)
            for(int j=0;j<=i;j++)
                for(int k=0;k<=i;k++)
                    for(int l=0;l<=k;l++)
                    {
                        dfs(i,j,k,l);
                        dfs(k,l,i,j);
                    }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=cnt[i];j++)(ans*=j)%=MOD;
        cout<<ans;
    }
    View Code

    Orz LZJ

    最后得分应该是80+100+50=230

    (第一题爆int咯妈了个zz)

    但是xgy错了一个价值80分的等号

    yyc错了价值...不知道多少分反正好多好多分的三个字符

    所以我好像是3个250中考的最高的Orz

  • 相关阅读:
    自动机
    C语言文法
    实验报告一:词法分析
    Python的基础综合练习
    Python基础综合练习
    turtle画五星红旗
    熟悉常用的Linux操作
    大数据概述
    对学习编译原理的看法
    LINUX
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/7689082.html
Copyright © 2020-2023  润新知