CF#612(Div.2)

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;
}

 

上一篇:python中将字符串和数值型连接—f“{}”


下一篇:Codeforces Round #624 (Div. 3) A. Add Odd or Subtract Even(水题)