Codeforces Round612(div2)——A-D题总结

比赛链接:https://codeforces.com/contest/1287

A题 Angry Students

题目大意:

给你一个只包含A和P的字符串,求每个A字符后面连续出现P字符的最大次数。

举个例子:APAPPAPPP 答案为3,因为最后一个A后面出现连续出现了3个P字符,出现次数是最大的。

Input

3
12
APPAPPPAPPPP
3
AAP
3
PPA

Output

4
1
0
题解:

直接维护一个记录A后面最大连续P出现次数的值就行了,注意特殊考虑一下没有出现A就出现P的情况。

代码实现:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
string s;
int main(){
    int T=read();
    while(T--){
        int n=read();
        cin>>s;
        int maxn=0,sum=-INF;
        rp(i,0,n-1){
            if(s[i]=='A') maxn=max(maxn,sum),sum=0;
            else    sum++;
        }
        maxn=max(sum,maxn);
        cout<<maxn<<endl;
    }
    return 0;
}

B题 Hyperset

题目大意:

给你两个整数n和k,然后给你n个长度为k的字符串(只含有'S','E','T')。

在这n个字符串中任选3个字符串,如果这三个字符串满足以下条件:

1.把这3个字符串的第k个位置的字符可以组合成"SET"

2.或者这三个字符串的第k个位置的字符都相同

则这三个字符串对答案的贡献为1。

求这n个字符串中满足条件的个数。

Input

5 4
SETT
TEST
EEET
ESTE
STES

Output

2

Note 

样例中符合条件的个数为2。分别是

1."SETT", "TEST", "EEET"

2."TEST", "ESTE", "STES"

题解:

这个题不要多想,能暴力就直接暴力,不过我们考虑枚举两个字符串,第三个字符串就定了,因此再用set找就行了。O(k*n^2*log(n))的时间复杂度可以过。

代码实现:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
const int N = 1507;
string s[N];
int cnt[10];
int n,K;
set<string> ss;
int main(){
    n=read(),K=read();
    rp(i,0,n-1) cin>>s[i],ss.insert(s[i]);
    // rp(i,0,n-1) cout<<s[i]<<endl;
    ll ans=0;
    rp(i,0,n-2){
        rp(j,i+1,n-1){
            string temp="";
            rp(k,0,K-1){
                if(s[i][k]==s[j][k]) temp+=s[i][k];
                else{
                    if((s[i][k]=='S'&&s[j][k]=='E')||(s[i][k]=='E'&&s[j][k]=='S')) temp+="T";
                    if((s[i][k]=='S'&&s[j][k]=='T')||(s[i][k]=='T'&&s[j][k]=='S')) temp+="E";
                    if((s[i][k]=='T'&&s[j][k]=='E')||(s[i][k]=='E'&&s[j][k]=='T')) temp+="S";
                }
            }    
            if(ss.find(temp)!=ss.end()) ans++;
        }
    }
    cout<<ans/3<<endl;
    return 0;
}

C题 Garland

题目大意:

首先定义一个排列的复杂度:满足排列中相邻位置的数,一个数为奇数,一个数为偶数的个数(即具有奇偶校验性)。

比如:1,4,2,3,5的复杂度为2,因为(1,4)和(2,3)满足条件。

然后给你n个数的一个排列,某些位置为0,表示该位置没有数。

因此你可以填补这个排列,但是要保证填补后排列的复杂度最小,求这个最小的排列复杂度。

Input

5
0 5 0 2 3

Output

2

Note

样例中符合条件的排列是1,5,4,2,3,这样排列复杂度最小,且排列复杂度为2

题解:

本来想的是可以贪心一下来做,就是奇数的放一起,偶数的放一起。但是这样如果时1,0,0,0,5的话就没法考虑,因此要考虑一种可以考虑所有情况,然后取最优的算法,不难想到dfs,但是2^100,肯定也不行,因此我们可以考虑记忆话搜索+dp来做,因为n最大为100,不难想到可以推一个O(n^3)的dp,虽然我没想到,还是dp做的少

首先定义状态为dp[i][o][e][k]表示考虑第i位数,当前奇数个数为o,偶数个数为e,k为1表示上一位为奇数,0表示上一位为偶数

状态转移方程:

当p[i]!=0时//当前位置有数

if(k==2&&p[i]%2==k) dp[i][o][e][k]=dp[i][o][e][p[i]%2] //位置为1时以及当前位的奇偶性和上一位相同

else dp[i][o][e][k]=dp[i][o][e][p[i]%2]+1 //当前位的奇偶性和上一位不同

当p[i]==0时//当前位置没有数

L为考虑填一个奇数的答案

R为考虑填一个偶数的答案

求L和R的时候需要考虑k==2,k==1,k==0的情况,考虑是否加1,即和上一位奇偶性是否相同

dp[i][o][e][k]=min(dp[i][o][e][k]+L,dp[i][o][e][k]+R)

思路大致清楚了,记忆话搜索一下就行了。

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
int p[105],visited[105];
vector<int> s1;
vector<int> s2;
int dp[105][105][105][2];
int n;
int dfs(int i,int odd_num,int even_num,int k){
    if(i==n+1) return 0;
    if(dp[i][odd_num][even_num][k]!=-1) return dp[i][odd_num][even_num][k];
    dp[i][odd_num][even_num][k]=0;
    if(p[i]!=0){
        if(k==2||p[i]%2==k) dp[i][odd_num][even_num][k]=dfs(i+1,odd_num,even_num,p[i]%2);
        else dp[i][odd_num][even_num][k]=dfs(i+1,odd_num,even_num,p[i]%2)+1;
    }
    else{
        int l=1005,r=1005;
        if(k==2){
            if(odd_num!=0) l=dfs(i+1,odd_num-1,even_num,1);
            if(even_num!=0) r=dfs(i+1,odd_num,even_num,0);
        }
        else if(k==1){
            if(odd_num!=0) l=dfs(i+1,odd_num-1,even_num,1);
            if(even_num!=0) r=dfs(i+1,odd_num,even_num-1,0)+1;
        }
        else if(k==0){
            if(odd_num!=0) l=dfs(i+1,odd_num-1,even_num,1)+1;
            if(even_num!=0) r=dfs(i+1,odd_num,even_num-1,0);
        }
        dp[i][odd_num][even_num][k]=min(dp[i][odd_num][even_num][k]+l,dp[i][odd_num][even_num][k]+r);
    }
    return dp[i][odd_num][even_num][k];
}
int main(){
    n=read();
    rp(i,1,n){
        p[i]=read();
        if(p[i]) visited[p[i]]=1;
    }
    rp(i,1,n){
        if(!visited[i]){
            if(i%2==1) s1.pb(i);
            else s2.pb(i);
        }
    }
    mst(dp,-1);
    printf("%d\n",dfs(1,s1.size(),s2.size(),2));
    return 0;
}
/*
7
1 3 5 7 0 0 0
1
7
0 0 0 0 0 0 0 
1
7 
0 0 0 7 6 4 2
5
1 0 2 0 5
2
7
1 3 5 0 6 4 2
1
7
1 0 0 5 0 0 2
1
20
9 0 0 0 18 0 11 0 0 4 0 15 0 0 0 14 0 0 5 0
8
20
7 0 9 0 5 0 15 0 0 1 17 0 11 19 0 0 3 0 13 0
15
*/

D题Numbers on Tree

题目大意:

首先定义一个节点的ci表示以这个树为根节点的子树中满足aj<ai的点的个数。

当然这个题不会让你求ci,不然就是一道sb题。

给你一颗树,以及每个节点的ci字,然后让你确定一下有没有满足条件的a数组,有的话输出YES并输出a数组,否则输出NO。a数组如果有多个,可以输出任意一个。

Input

5
0 1
1 3
2 1
3 0
2 0
Output

YES
2 3 2 1 2

题解:

首先这个题的数据范围很小,所以我们可以考虑暴力维护一下子树的答案就行了,首先考虑怎么求出一个子树的答案。

如果这个子树的根节点的值为ci,表示子树中有ci个节点的a值小于它。

然后根据这个性质,我们可以暴力求出当前子树的a数组,然后把根节点插入到第ci+1位,后面的依次往后移就行了。

这样时间复杂度为O(n^2)的,其实这个题数据范围可以开大点,开到1e5都行,这样的话就需要用到dsu on tree,时间复杂度大致为O(nlogn)。

代码实现:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
const int N = 2e3+7;
vector<int> G[N];
int res[N],c[N];
int n;
vector<int> dfs(int x){
    vector<int> ans;
    for(auto v:G[x]){
        vector<int> tmp=dfs(v);
        for(auto val:tmp) ans.pb(val);
    }
    if(x==0) return ans;
    if(ans.size()<c[x]){
        cout<<"NO"<<endl;
        exit(0);
    }
    vector<int> temp;
    rp(i,0,c[x]-1) temp.pb(ans[i]);
    temp.pb(x);
    rp(i,c[x],(int)ans.size()-1) temp.pb(ans[i]);
    ans=temp;
    return ans;
}
int main(){
    n=read();
    rp(i,1,n){
        int x=read();
        c[i]=read();
        G[x].pb(i);
    }
    vector<int> ans=dfs(0);
    cout<<"YES"<<endl;
    rp(i,0,ans.size()-1) res[ans[i]]=i+1;
    rp(i,1,n) cout<<res[i]<<" ";
    cout<<endl;
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值