zoukankan      html  css  js  c++  java
  • Codeforces Round #533 (Div. 2)

    Codeforces Round #533 (Div. 2)题解

    A

    题意:
    给你一个序列,你可以修改序列中的每个数使其变成一个另一个正整数,如a-->b代价为abs(a-b)
    求一个t是的修改后的(abs)(a[i]-t)<=1,求最小代价
    题解:
    因为a很小枚举即可

    #include<bits/stdc++.h>
    using namespace std;
    int a[1005];
    int main()
    {
        int n;
        scanf("%d",&n);
        for (int i=1; i<=n; i++) scanf("%d",&a[i]);
        int ans1=2000000000,ans2=a[n];
        for (int t=1; t<=100; t++)
        {
            int sum=0;
            for (int j=1; j<=n; j++)
            {
                int zz=2000000000;
                for (int tt=t-1; tt<=t+1; tt++) if (tt>0)
                {
                    zz=min(zz,abs(tt-a[j]));
                }
                sum+=zz;
            }
            if (sum<ans1)
            {
                ans1=sum; ans2=t;
            }
        }
        printf("%d %d
    ",ans2,ans1);
    }
    

    B

    题意:
    给一个字符串和k,连续k个相同的字符,可使等级x加1,
    例:8 2 aaacaabb 则有aa aa 即x=2。 求最大的x
    题解:
    O(N)扫一遍,对于每一段统计一下答案

    #include<bits/stdc++.h>
    using namespace std;
    int n,k;
    char s[200005];
    int sum[10000];
    int main()
    {
        scanf("%d%d",&n,&k);
        scanf("%s",s+1);
        int pre=0,ans=0,len=0;s[n+1]='A'-1;
        for (int i=1; i<=n+1; i++)
        {
            int x=s[i]-'A'+1;
            if (x!=pre)
            {
    
                sum[pre]+=len/k;
                //cout<<x<<" "<<sum[x]<<" "<<len/k<<endl;
                ans=max(ans,sum[pre]);
                len=1;
            }
            else len++;
            pre=x;
        }
    
        printf("%d
    ",ans);
        return 0;
    }
    

    C

    题意:
    一个n长的数组每个位置可以填区间l-r的值。
    有多少种填法,使得数组每个位置相加的和是3的倍数
    题解:
    统计一下l到r mod 3为0、1、2的个数 之后DP一下就可以了

    #include<bits/stdc++.h>
    #define N 200005
    #define mod 1000000007
    using namespace std;
    long long  f[N][4];
    int n,l,r;
    long long a[4];
    int main()
    {
        scanf("%d%d%d",&n,&l,&r);
        a[0]=a[1]=a[2]=(r-l+1)/3;
        int xx=(r-l+1-a[0]*3);
        if (xx==1)
        {
            if (r%3==0) a[0]++;
            if (r%3==2) a[2]++;
            if (r%3==1) a[1]++;
        }
        else if (xx==2)
        {
            a[0]++; a[1]++; a[2]++;
            if (r%3==0) a[1]--;
            if (r%3==2) a[0]--;
            if (r%3==1) a[2]--;
        }
       // cout<<" "<<a[0]<<" "<<a[1]<<" "<<a[2]<<endl;
        f[1][1]=a[1];
        f[1][2]=a[2];
        f[1][0]=a[0];
        for (int i=2; i<=n; i++)
        {
            f[i][0]=((f[i-1][0]*a[0]%mod+f[i-1][1]*a[2]%mod)%mod+f[i-1][2]*a[1]%mod)%mod;
            f[i][1]=((f[i-1][0]*a[1]%mod+f[i-1][1]*a[0]%mod)%mod+f[i-1][2]*a[2]%mod)%mod;
            f[i][2]=((f[i-1][0]*a[2]%mod+f[i-1][1]*a[1]%mod)%mod+f[i-1][2]*a[0]%mod)%mod;
    
        }
        printf("%lld",f[n][0]);
        return 0;
    }
    

    D

    题意:
    给n*m的地图,最多9个人,同时有每个人的扩张次数(我开始以为是直线扩张最大长度。。实际是能连续扩张次数。)
    地图上有‘#’,‘.',和数字,数字对应每个人的据点,
    从1-n轮流扩张。
    地图被扩张完后,输入每个人的据点数目。
    题解:
    开p个队列,模拟一下就可以了

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,p;
    int dx[5]={0,0,-1,1},dy[5]={1,-1,0,0};
    struct Node{
        int x,y;
    };
    queue<Node> q[20];
    int ans[20],speed[20];
    char s[1005][1005];
    void run(int i)
    {
        for (int tt=q[i].size()-1; tt>=0; tt--)
        {
            Node nownode=q[i].front(); ans[i]++;
            q[i].pop();
            for (int k=0; k<4; k++)
            {
                int xx=nownode.x+dx[k],yy=nownode.y+dy[k];
                if (xx<1 || xx>n || yy<1 || yy>m) continue;
                if (s[xx][yy]=='.')
                {
                    s[xx][yy]='0'+i;
                    Node newnode={xx,yy};
                    q[i].push(newnode);
                }
            }
        }
    }
    void init()
    {
        scanf("%d%d%d",&n,&m,&p);
        for (int i=1; i<=p; i++) scanf("%d",&speed[i]);
        for (int i=1; i<=n; i++)
        {
            scanf("%s",s[i]+1);
            for (int j=1; j<=m; j++)
            {
                if (s[i][j]=='.' || s[i][j]=='#') continue;
                int X=s[i][j]-'1'+1;
                Node newnode={i,j};
                q[X].push(newnode);
            }
        }
    }
    int main()
    {
        init();
        while (true)
        {
            for (int i=1; i<=p; i++)
            {
                for (int j=1;  (!q[i].empty() && j<=speed[i]);  j++) run(i);
            }
            int sum=0;
            for (int i=1; i<=p; i++) sum+=q[i].size();
            //cout<<sum<<endl;
            if (sum==0) break;
        }
        for (int i=1; i<=p; i++) printf("%d ",ans[i]);
    }
    

    E

    题意:
    有 n 个事件,op = 1 表示我可以修改昵称,op = 2 表示一个名为 s_i 的朋友查询我当前的名字。一个朋友是高兴的当且仅当他每次查询我的名字都为 s_i,保证每个朋友至少查询一次我的名字,问最多可以有多少个朋友高兴。

    题解:
    之前以为只要高兴一次就可以了 后面才发现每次高兴才算高兴

    只高兴一次就算高兴的话 可以用网络流写
    1.对于每次修改账号的点 从S连一条容量为1的边
    2.对于每次查询,从之前的修改向其连一条容量为1的边
    3.对于每个人向T连一条容量为1的边

    #include<bits/stdc++.h>
    #define N 1005
    #define INF 100000000
    using namespace std;
    int n,m;
    int ans;
    int tot1,tot2;
    map<string,int> mp;
    struct Edge{
        int from,to,cap,flow,pre;
    };
    struct Dinic{
        int n,m,s,t,edgenumber;
        int now[N],dis[N];
        bool vis[N];
        vector<Edge> edges;
        void preclear()
        {
            edgenumber=0;
            edges.clear();
            memset(now,-1,sizeof(now));
        }
       void AddEdge(int from,int to,int cap)
       {
          // cout<<"           "<<from<<" "<<to<<" "<<cap<<endl;
            Edge E1={from,to,cap,0,now[from]};
            edges.push_back(E1);
            now[from]=edgenumber++;
            Edge E2={to,from,0,0,now[to]};
            edges.push_back(E2);
            now[to]=edgenumber++;
        }
        bool BFS()
        {
            queue<int> Q;
            memset(vis,0,sizeof(vis));
            memset(dis,-1,sizeof(dis));
            Q.push(s); vis[s]=1;
            while (!Q.empty())
            {
                int x=Q.front(); Q.pop();
                //cout<<x<<endl;
                for (int p=now[x]; p!=-1; p=edges[p].pre)
                {
                    Edge e=edges[p];
    
                    if (!vis[e.to] && e.cap>e.flow)
                    {
                        vis[e.to]=1; dis[e.to]=dis[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
        int dfs(int x,int a)
        {
            if (x==t || a==0)
            {
                return a;
            }
            int flow=0,f;
            for (int p=now[x]; p!=-1; p=edges[p].pre)
            {
                Edge e=edges[p];
                if (dis[e.to]==dis[x]+1 && (f=dfs(e.to,min(a,e.cap-e.flow))) >0)
                {
                    edges[p].flow+=f;
                    edges[p^1].flow-=f;
                    a-=f;
                    flow+=f;
                    if (a==0) break;
                }
            }
            return flow;
        }
        int maxflow(int s,int t)
        {
            this -> s=s;
            this -> t=t;
            int flow=0;
            while (BFS())
            {
                //cout<<"shit"<<endl;
                flow+=dfs(s,INF);
            }
            return flow;
        }
    }D;
    
    int main()
    {
        D.preclear();
        scanf("%d%d",&n,&m);
        int pre=-1,prex=0,s,t; tot1=1;
        s=0;    t=1;
        for (int i=1; i<=n; i++)
        {
            int type;
            scanf("%d",&type);
            if (type==1)
            {
                ++tot1;
                pre=tot1;
                prex=1;
            }
            else
            {
               string ss;
                if (prex==1)
                D.AddEdge(s,pre,1);
               cin>>ss;
               if (mp.find(ss)==mp.end())
               {
                   mp[ss]=++tot1;
    
                   D.AddEdge(mp[ss],t,1);
               }
               if (pre!=-1) D.AddEdge(pre,mp[ss],1);
               prex=2;
            }
        }
        cout<<D.maxflow(s,t)<<endl;
        return 0;
    }
    

    每次高兴才算高兴的话
    其实就是对于一段连续的查询操作统计答案时最多只能统计一次
    所以对于一段连续的查询操作中任意两点连边所形成的图的 补集的最大团就是答案
    之后利用最大团的随机算法就好
    至于随机算法证明我就只能告诉你应该和概率相关,具体不会证明

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,k,a[50],b[50],tot;
    bool vis[50][50];
    string ss;
    map<string,int>mp;
    bitset<50>s,ans;
    void work1()
    {
        for (int i=1; i<=a[0]; i++)
        {
            for (int j=i+1; j<=a[0]; j++)
                vis[a[i]][a[j]]=vis[a[j]][a[i]]=false;
        }
        a[0]=0;
    }
    void work2()
    {
        if (!mp.count(ss)) mp[ss]=++tot;
        a[++a[0]]=mp[ss];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        memset(vis,true,sizeof(vis));
        for (int i=1; i<=n; i++)
        {
            int type;
            scanf("%d",&type);
            if (type==1) work1();
            else cin>>ss,work2();
        }
        work1();
        int T=5e4;
        for (int i=1; i<=m; i++) b[i]=i;
        while (T--)
        {
            random_shuffle(b+1,b+m+1);
            for (int i=1; i<=m; i++) s[i]=1;
            for (int i=1; i<=m; i++)
            {
                if (s[b[i]]==1)
                {
                    for (int j=i+1; j<=m; j++)
                    {
                        if (!vis[b[i]][b[j]]) s[b[j]]=0;
                    }
                }
            }
            if (s.count()>ans.count()) ans=s;
        }
        cout<<ans.count()<<endl;
    }
    
  • 相关阅读:
    横竖屏切换
    org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 0: unknown encoding
    @Value() 使用方法
    调用第三方超时处理
    spring 配置注解定时器quartz01
    tomcat:PermGen space
    06-图3 六度空间 (30分)
    06-图2 Saving James Bond
    06-图1 列出连通集 (25分)
    05-树9 Huffman Codes (30分)
  • 原文地址:https://www.cnblogs.com/HQHQ/p/10298298.html
Copyright © 2011-2022 走看看