ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF#612(Div.2)

2020-02-05 22:55:00  阅读:314  来源: 互联网

标签:even pre 612 CF int Div.2 长度 include odd


CF#612(Div.2)

A. Angry Students

题意:

给你一个字符串(只包含’A’,’P’),每过1秒, 对于每一个A,假如它右边那个不是A,它会把他右面那个变成A。问最多过几秒,整个串中A的数目不会增加

思路

这题数据范围非常小,因此可以用bfs求解

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int vis[150];
int ans = 0;
void solve(int n)
{
    queue<int> q;
    for(int i = 1;i<=n;++i)
        if(vis[i]==0)
            q.push(i);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        ans = max(ans,vis[x]);
        if(x+1<=n&&vis[x+1]==-1)
        {
            vis[x+1] = vis[x]+1;
            q.push(x+1);
        }
    }
    return ;
}
int main()
{
  int t;
  cin >> t;
  while(t--)
  {
      int n;
      cin >> n;
      for(int i = 1;i<=n;i++)
        vis[i] = -1;
      string s;
      cin >> s;
      for(int i = 0;i<n;i++)
      {
          if(s[i]=='A')
            vis[i+1] = 0;
      }
      ans = 0;
      solve(n);
      ans = max(ans,0);
      cout << ans << endl;
  }
    return 0;
}

 

B. Hyperset

题意:

给你n个长度为k的字符串(只包括"S", "E", or "T".),对于每三个串,如果这三个串每一个元素完全相同或者完全不同,可以称为一个set,问总共有几对set。

思路:

这里的数据范围是比较小的,我们可以通过枚举两个串然后根据上面的条件构造出第三个串来,检查一下这个串是否存在就行,要注意我们这样枚举的话每一组合是数了3次的,所以要除以3。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1500+10;
string str[maxn];
set<string> s;
int main()
{
   int n,k;
   cin >> n >>k;
   for(int i = 0;i<n;++i)
   {
       cin >>str[i];
       s.insert(str[i]);
   }
   int all = 'S'+'T'+'E';
   string q ;
   q.resize(k);
   int res = 0;
   for(int i = 0;i<n;i++)
   {
       for(int j = i+1;j<n;++j)
       {
           for(int l = 0;l<k;++l)
           {
               if(str[i][l]==str[j][l])
               {
                   q[l] = str[i][l];
               }
               else
               {
                   q[l] = all-str[i][l]-str[j][l];
               }
           }
           if(s.find(q)!=s.end())
            ++res;
       }
   }
   cout << res/3 << endl;
    return 0;
}

 

C. Garland

题意:

给一个1-n的排列,但排列中的某些数被移去了,,定义一个概念complexity它的值为排列中奇偶性不同的相邻两数的对数。,要求输出complexity值最小的排列。

思路:

定义一个四维dp数组 dp[i][even][odd][2] ,代表到第i个位置时,已经填了even个偶数,odd个奇数,此时在第i个位置填入(奇数或偶数)的最小答案。

在探讨转移方程之前,我们需要先计算总共空出多少个偶数和奇数,以及在第i个位置之前一共有多少个待填位置,定义为pre[i]。

我们首先要枚举前三维,假如现在枚举的偶数以及奇数数目符合要求,这时如果当前位置已经有数,

如果是奇数,若上一位为偶数,则对答案贡献+1。

f[i][j][k][0] = min(f[i - 1][j][k][0], f[i - 1][j][k][1] + 1);

若是偶数

f[i][j][k][1] = min(f[i - 1][j][k][0] + 1, f[i - 1][j][k][1]);

如果当前位置已经没有数,则需要两种情况都要考虑,同时要注意的时,我们现在是需要往里面填数的,所以转移方程略有不同。

f[i][j][k][0] = min(f[i - 1][j - 1][k][0], f[i - 1][j - 1][k][1] + 1);

f[i][j][k][1] = min(f[i - 1][j][k - 1][0] + 1, f[i - 1][j][k - 1][1]);

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
const int N = 105;
int f[N][N][N][2]={0};
int a[N];
int pre[N];
int odd, even;
int main()
{
    int n;
    scanf("%d", &n);
 
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[i]);
        if (a[i] > 0)
        {
            if (a[i] % 2 == 0)
                ++even;
            else
                ++odd;
            pre[i] = pre[i - 1];
        }
        else
        {
            pre[i] = pre[i - 1] + 1;
        }
    }
 
    if (n % 2 == 0)
    {
        even = n / 2 - even;
        odd = n / 2 - odd;
    }
    else
    {
        even = n / 2 - even;
        odd = n / 2 + 1 - odd;
    }
        memset(f, 0x3f, sizeof f);
    //第二维和第三维为填充的偶数个数和奇数个数
   // cout << 0x3f<< endl;
    f[0][0][0][0] = 0;
    f[0][0][0][1] = 0;
 
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 0; j <= even; ++j)
        {
            for (int k = 0; k <= odd; ++k)
            {
                if (a[i] > 0)
                {
                    if (j + k <= pre[i])
                    {
                        if (a[i] % 2 == 0)
                        {
                            f[i][j][k][0] = min(f[i - 1][j][k][0], f[i - 1][j][k][1] + 1);
                        }
                        else
                        {
                            f[i][j][k][1] = min(f[i - 1][j][k][0] + 1, f[i - 1][j][k][1]);
                        }
                    }
                }
                else
                {
                    if (j + k <= pre[i])
                    {
                        f[i][j][k][0] = min(f[i - 1][j - 1][k][0], f[i - 1][j - 1][k][1] + 1);
                        f[i][j][k][1] = min(f[i - 1][j][k - 1][0] + 1, f[i - 1][j][k - 1][1]);
                    }
                }
            }
        }
    }
 
    int res = 0x3f3f3f3f;
    res = min(f[n][even][odd][0], f[n][even][odd][1]);
 
    printf("%d\n", res);
 
 
    return 0;

 

D. Numbers on Tree

题意:

给你一个有根树,对于这棵树,每一个结点上都有一个数字ai,同时定义一个值ci,代表第以第i个结点为根的子树中值比自己大的数的根数,现在给出每个节点的父节点以及ci,请输出YES和任何符合条件的a数组或NO。

思路:

首先通过给出的信息,我们能够构造出这棵树,对于每个结点i,我们可以得到它的子树上有多少个结点,定义为sub[i]。假如子树上的结点数要比给出的c值要小,则一定输出NO,为了简便思考,我们可以假定a数组是1-n的一个排列,对于每一个结点,我们只要保证正好有c[i]个没有被选取的数即可,详细细节可以看代码。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e3+3;
int n,c[N],ans[N],sub[N];
bool vis[N],f;
vector<int>pic[N];
void dfs(int num)
{
    if(!f)
        return ;
    int cnt = 0;
    for(int i = 1;i<=n;++i)
    {
        if(!vis[i])
            cnt++;
        if(cnt==c[num]+1)
        {
            ans[num] = i;
            vis[i] =1;
            break;
        }
    }
    for(int i = 0;i<pic[num].size();++i)
    {
        dfs(pic[num][i]);
        sub[num]+=sub[pic[num][i]];
    }
    if(sub[num]<c[num])
    {
        f = 0;
        return;
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        int root,p;
        for(int i = 0;i<=n;++i)
            pic[i].clear();
        memset(ans,0,sizeof(ans));
        memset(vis,0,sizeof(vis));
        for(int i =1;i<=n;++i)
        {
            scanf("%d %d",&p,&c[i]);
            if(p==0)
                root= i;
            else
                pic[p].push_back(i);
        }
        for(int i = 1;i<=n;++i)
        {
            sub[i] = pic[i].size();
        }
        f = 1;
        dfs(root);
        if(f)
        {
            printf("YES\n");
            for(int i = 1;i<=n;++i)
            {
                printf("%d%c",ans[i],i==n?'\n':' ');
            }
        }
        else
            printf("NO\n");
    }
    return 0;
}

 

E1. Madhouse (Easy version)

题意:

交互题,题目给出一个字符串的长度为n,你可对其进行不超过三次询问,格式为

? l  r 系统会返回s[l]-s[r]的所有子串(每个子串是乱序的),同时要求总返回的子串数不能超过(n+1)^2。

然后要求输出该字符串是什么,格式为

!s

思路:

这个题事实上只需要询问两次就够了,一个是1-n,另一个是2-n。下面简述下做法

以abcd为例吧

第一次询问

长度为1:a , b , c ,d

长度为2:ab, bc, cd

长度为3:abc,bcd

长度为4:abcd

第二次询问

长度为1:b , c ,d

长度为2:bc, cd

长度为3:bcd

通过观察我们可以发现,

长度为1时,第一次比第二次多一个字符串a,我们这样就得到字符串的第1个元素。

长度为2时,第一次比第二次多出ab,此时a是我们已知的元素,而b正好是第二个元素。

以此类推,就可以得到最终结果。

最后要特判n=1时的情况。

代码:

#include <bits/stdc++.h>
using namespace std;
vector<string>vec[105];
map<string,int>mp,mp1;
string ans;
int n;
void solve()
{
    ans.resize(n);
    int res = 0;
    for(int i = 1;i<=n;++i)
    {
        mp1.clear();
        string tmp;
        for(int j = 0;j<vec[i].size();++j)
        {
            mp1[vec[i][j]]++;
        }
        for(int j = 0;j<vec[i].size();++j)
        {
            if(mp.find(vec[i][j])==mp.end()||mp[vec[i][j]]!=mp1[vec[i][j]])
            {
                tmp = vec[i][j];
            }
        }
        int sum = 0;
        for(int i = 0;i<tmp.size();++i)
        {
            sum+=(tmp[i]-'a');
        }
        ans[i-1] = sum-res+'a';
        res = sum;
    }
    cout << "! " << ans << endl;
}
int main()
{
   // int n;
    cin >> n;string s;
    if(n==1)
    {
        cout << "? 1 1" << endl;
 
        cin >> s;
        cout << "! " << s << endl;
    }
    else
    {
        cout << "? 1 " << n << endl;
        for(int i = 0;i<n*(n+1)/2;++i)
        {
            cin >> s;
            sort(s.begin(),s.end());
            vec[s.size()].push_back(s);
        }
        cout << "? 2 " << n << endl;
        for(int i = 0;i<n*(n-1)/2;++i)
        {
            cin >> s;
            sort(s.begin(),s.end());
            mp[s]++;
        }
        solve();
    }
    return 0;
}

 

标签:even,pre,612,CF,int,Div.2,长度,include,odd
来源: https://www.cnblogs.com/baihualiaoluan/p/12267106.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有