CHD2017校赛题解

来源:互联网 发布:php 根据ip 查询地区 编辑:程序博客网 时间:2024/05/21 02:49

B. Boy and Girls

题目链接

题意:给一串含有n个Gn个B的字符串, 交换相邻字符,使字符串达到GBGBGB  /  BGBGBG,求最小交换次数;

解法:暴力扫字符串,出现不满足条件的情况,就在后边找到相应的字符。O(n^2)绝对超时;因此,不能扫。换一个思路,从末状态开始入手,每一个B/G都要到达位置1,3,5,7,9 / 2,4,6,8,10,而将一个字符从位置x1移动到x2,需要交换|x1-x2|次,因此只需计算|x1-1|+|x2-3|+|x3-5|+...+|xn-2*n+1|和|x1-2|+|x2-4|+|x3-6|+...+|xn-2*n|,取最大值即可

#include <cstdio>#include<queue>#include<cstdlib>#define ll long longusing namespace std;ll T,n;char s[200005];queue<ll> q;int main(){    scanf("%lld",&T);    while(T--)    {        scanf("%lld",&n);        scanf(" %s",s);        for(int i=0;i<2*n;i++)        {            if(s[i]=='B')            {                q.push(i);            }        }        ll k1=0,k2=1,sum1=0,sum2=0;        while(!q.empty())        {            ll x=q.front();            q.pop();            sum1+=abs(k1-x);            sum2+=abs(k2-x);            k1+=2;            k2+=2;        }        printf("%lld\n",min(sum1,sum2));    }    return 0;}

E.Colorful Ribbon

题目链接

题目类型:dp

题意:将给定只包含小写字符的字符串,分为没有重复的几段,问有多少种分法

解法:dp[i]表示前i个字符可以分为几段,转移方程为dp{i}=sum(dp[k])  (k = p ~ i-1 ),p表示当前串,上一个断点能取到的中,最靠前的那个字符的位置

#include <iostream>#include<stdio.h>#include<cstring>#include<algorithm>#define ll long longusing namespace std;const int inf=0x3f3f3f3f3f3f;int T,vist[30],p;ll dp[100005];char s[100005];const ll MOD = 1000000000+7;int main(){    scanf("%d",&T);    while(T--)    {        memset(s,0,sizeof(s));        scanf(" %s",s+1);        memset(dp,0,sizeof(dp));        int len = strlen(s+1);        memset(vist,0,sizeof(vist));        dp[0]=1;        p=-1;        for(int i=1;i<=len;i++)        {            p=max(vist[s[i]-'a'],p);            for(int j=p;j<i;j++)            {                dp[i]+=(dp[j]%MOD);            }            vist[s[i]-'a']=i;        }        cout << dp[len]%MOD << endl;    }    return 0;}


J.Repeated String

题目链接

题意:构造长度为n的B,使得与A的distance最小;

题解:暴力枚举a-z,判断每一位的B上的字母应该是什么。O(26*n*m)

Code:(不知道为啥RE,然后又TE,以后知道哪错了,就补代码)


L.QAQ Number

题目链接

题意:计算出指定范围内,符合条件的数字的个数

题解:现场想法是利用10^0-10^3有90个,10^6-10^9有90个.....10^15-10^18有90个,将完全包含的区间加上去,左右边界单独处理,处理时发现,右边界数量级很大,不能个暴力,然后队友想了个判断方法,异常难写啊。。。最后,这写法估计要代码200+。。。放弃了。下场才知道,这个神奇做法。

因为,通过检测方法实现数量很大,所以说明在给定范围的答案不多,因此直接从答案入手,枚举Q,B即可,可以利用;有个小问题:就是B为0的时候,方法1。特判B为0,00,000...时,方法2,vist[]标记这个数是否被访问过;

#include <cstdio>#include<queue>#include<cstdlib>#define ll long longusing namespace std;ll T,n;char s[200005];queue<ll> q;int main(){    scanf("%lld",&T);    while(T--)    {        scanf("%lld",&n);        scanf(" %s",s);        for(int i=0;i<2*n;i++)        {            if(s[i]=='B')            {                q.push(i);            }        }        ll k1=0,k2=1,sum1=0,sum2=0;        while(!q.empty())        {            ll x=q.front();            q.pop();            sum1+=abs(k1-x);            sum2+=abs(k2-x);            k1+=2;            k2+=2;        }        printf("%lld\n",min(sum1,sum2));    }    return 0;}


0 0