bestcoder 92

Skip the Class

Accepts: 678
Submissions: 1285
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
终于又开学啦。呃喵最喜欢的就是开学了,因为这样她又可以愉快地翘课了(啊?)
呃喵接下来有n节课程需要上(换句话说,可以翘。)
每节课程有相应的课程类型与课程翘课价值。
有一点需要注意的是,呃喵不可以翘同一类课程超过两次,就是如果这类课已经翘了两次,接下来就一定要上。
问你在这个条件下,呃喵可以获得的最大翘课价值。
输入描述
第一行为一个整数T,代表数据组数。
接下来,对于每组数据——
第一行一个整数n,表示接下来需要依次上的课程数量,
接下来有n行,每行包括一个仅由'a'~'z'构成的长度不超过10的字符串s与一个正整数v。
其中字符串表示课程的类型,相同的字符串代表相同的课程。

数据保证——
1 <= T <= 1000
对于每组数据,1 <= n <= 100,1 <= |s| <= 10, 1 <= v <= 1000
输出描述
对于每组数据,输出一行。
该行有1个整数,表示呃喵可以获得的最大翘课价值。
输入样例
2
5
english 1
english 2
english 3
math 10
cook 100
2
a 1
a 2
输出样例
115
3

对课程排个序,取前两名即可。
#include <iostream>
#include<bits/stdc++.h>

using namespace std;

const int N=1100;

struct node
{
    int v;
    char s[20];
}a[N];

bool cmp(node a,node b)
{
    if(strcmp(a.s,b.s)==0)
    {
        return a.v>b.v;
    }
    return strcmp(a.s,b.s)<0;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%s%d",a[i].s,&a[i].v);
        }
        sort(a,a+n,cmp);
        int t;
        int ans=0;
        for(int i=0;i<n;i++)
        {
            if(i==0||strcmp(a[i].s,a[i-1].s)!=0)
            {
                ans+=a[i].v;
                t=1;
            }
            else if(strcmp(a[i].s,a[i-1].s)==0&&t<2)
            {
                t++;
                ans+=a[i].v;
            }
        }
        cout<<ans<<endl;
    }
}

Count the Sheep

Accepts: 227
Submissions: 805
Time Limit: 3000/1500 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
开学翘课固然快乐,然而也有让呃喵抓狂的事,那当然就是考试了!这可急坏了既要翘课又想要打BC还要准备考试的呃喵。
呃喵为了准备考试没有时间刷题,想打BC又不想跌分,只得求助于BCround92的出题人snowy_smile,让他说点什么 ~~>_<~~。
snowy_smile实在没有办法,但是又不好意思透题,只好告诉呃喵,当务之急是好好休息。
"如果你按照下面这个办法睡着,那么第二天就绝对不会在BC的赛场上跌分——
想象一片一望无际、广阔无边的青青草原,草原上住着一群羊,包括n只沉默的男羊和m只流泪的女羊,在男羊和女羊之间,存在k个朋友关系。
现在你可以以任意一只羊为起点,顺着朋友关系数下去。如果能够连续数4只各不相同的羊,就能超过99%的数羊者,成功入睡。"
呃喵听后十分震惊,但她还是听话地数下去,果然,数到第4只羊就睡着了,并一口气睡过了头,成功地错过了第二天的BestCoder,真的不会在BC的赛场上跌分啦!
然而你,可就没有这么好的运气了,你既然看到了这第二题,自然一般已有提交,已经无法回头了。
面对"不AC这题就可能跌分"窘境的你,需要说出,呃喵在睡前可能有多少种不同的数羊序列。
即输出"A-B-C-D"这样序列的方案数,满足A-B、B-C、C-D是朋友关系且A、B、C、D各不相同。
输入描述
第一行输入数据组数T
对于每组数据,第一行有三个整数n, m, k,表示n只男羊编号分别为1~n,m只女羊编号分别为1~m,并且存在k个朋友关系。
接下来给出k行,每行给出两个数x y,表示第x只男羊和第y只女羊是朋友。

数据保证——
不会给出重复的朋友关系
1 <= T <= 1000
对于30%的数据,1 <= n, m, k <= 100
对于99%的数据,1 <= n, m, k <= 1000
对于100%的数据,1 <= n, m, k <= 100000
输出描述
对于每组数据,输出一行,该行包含一个整数,表示呃喵睡觉前可能数了哪4只羊的序列的方案数。
输入样例
(为了方便阅读,样例输入中数据组间中会额外添加一行空行)
3
2 2 4
1 1
1 2
2 1
2 2

3 1 3
1 1
2 1
3 1

3 3 3
1 1
2 1
2 2
输出样例
8
0
2
Hint
第一组样例:(b1-g1-b2-g2) (b1-g2-b2-g1) (b2-g1-b1-g2) (b2-g2-b1-g1) (g1-b1-g2-b2) (g1-b2-g2-b1) (g2-b1-g1-b2) (g2-b2-g1-b1) 共8种合法序列

公羊和母羊构成一个二分图,而遍历四只不同的羊需要连续的三条线段。考虑三条线段中间的那条线段,连接两端的端点a、b,(a的度-1)*(b的度-1)等于这条线段能取得的方案数。遍历所有的关系, 把它们作为中间线段考虑即可。最后的答案*=2。时间复杂度为o(k),比题解好一些……

#include <iostream>
#include<bits/stdc++.h>
#define ll __int64
using namespace std;

const int N=110000;
int dl[N],dr[N],l[N],r[N];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        memset(dl,0,sizeof(dl));
        memset(dr,0,sizeof(dr));
        for(int i=0;i<k;i++)
        {
            scanf("%d%d",&l[i],&r[i]);
            dl[l[i]]++;
            dr[r[i]]++;
        }
        ll ans=0;
        for(int i=0;i<k;i++)
        {
            ll ld=dl[l[i]],rd=dr[r[i]];
            ans+=(ld-1)*(rd-1);
        }
        ans*=2;
        printf("%I64d\n",ans);
    }
}

Girls Love 233

Accepts: 30
Submissions: 218
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
除了翘课以外,结识新的妹子也是呃喵重要的日程安排之一。
这不,呃喵又混进了一个叫做ACgirls的女生群里,来达成自己不可描述的目的。
然而,呃喵只会喵了个咪地说话,于是很容易引起注意。为了掩饰自己的真实身份,呃喵每次说话都小心翼翼。
她知道,很多女生都喜欢说"233",然而呃喵想说的话一开始就确定好了,所以她要对这句话做修改。
这句话的长度为n,语句里的字符不是'2'就是'3'。
呃喵的智力非常有限,只有m点。她每次操作可以交换两个相邻的字符,然而代价是智力-2。
现在问你,在使得自己智力不降为负数的条件下,呃喵最多能使这个字符串中有多少个子串"233"呢?
如"2333"中有一个"233","232323"中没有"233"
输入描述
第一行为一个整数T,代表数据组数。
接下来,对于每组数据——
第一行两个整数n和m,分别表示呃喵说的字符串长度 以及呃喵的智力
第二行一个字符串s,代表呃喵具体所说的话。

数据保证——
1 <= T <= 1000
对于99%的数据,1 <= n <= 10, 0 <= m <= 20
对于100%的数据,1 <= n <= 100, 0 <= m <= 100
输出描述
对于每组数据,输出一行。
该行有1个整数,表示最多可使得该字符串中有多少个"233"
输入样例
3
6 2
233323
6 1
233323
7 4
2223333
输出样例
2
1
2

这题场上爆搜T了,之后用题解的方法过了:

首先,因为字符不是'2'就是'3',所以我们可以把字符串当做一个全部都是'3'的串,然后有若干的'2'插入到了某些位置。
显然,我们交换相邻的'2'与'2'或者相邻的'3'与'3'是没有意义的,我们只会进行相邻'2'与'3'之间的交换。因此,所有'2'的相对前后关系其实是不会变化的。
做了这些比较基础的分析之后,基于数据规模很小,我们可以用以下4个要素表示完整的状态:
1.处理到第几个'2'
2.最后一个'2'停留在什么位置,如果当前的'2'与上一个'2'距离相差>=2时则对答案+1
3.呃喵的剩余交换次数是多少
4.当前已经成功得到几个"233"
而这四个要素的大小,最坏情况下分别是n、n、m、n级别的数,我们随便以3个要素作为下标对应状态,使得第4个要素最优做DP. 转移的时候步长也是不超过2m的,所以很容易就可以得出复杂度为O(n * n * m/2 * m)的算法,这个对于本题的时限和数据,没有什么作死写法的话是可以完全无压力顺利AC的。

题解说的第二个优化方法感觉可行,在标程的代码上感觉处理的有点疑问(没看懂- -),所以放弃了。
#include <iostream>
#include<bits/stdc++.h>

using namespace std;

const int N=105;

int n,T,m,cnt2,f[N][N][N],g[N];
char s[N];
int v[N][N][N];//ʡȥmemset

int dfs(int num2,int lastpos,int lastm)
{//cout<<num2<<" "<<lastpos<<" "<<lastm<<endl;
    if(num2 > cnt2)  return n-lastpos >= 2;
    if(v[num2][lastpos][lastm] == T + 1)  return f[num2][lastpos][lastm];
    v[num2][lastpos][lastm] = T + 1;
    int l = max(lastpos + 1,g[num2] - lastm);
    int r = min(n,g[num2] + lastm);
    f[num2][lastpos][lastm] = -1e9;
    for(int i = l;i <= r;i++)
    {
        int cost = abs(i - g[num2]);
        int t = dfs(num2 + 1,i,lastm - cost)+(i - lastpos >= 3) * (num2 > 1);
        if(t > f[num2][lastpos][lastm])
            f[num2][lastpos][lastm] = t;
    }
    return f[num2][lastpos][lastm];
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        m /= 2;
        scanf("%s",s + 1);
        cnt2 = 0;
        for(int i = 1; i <= n; i++)
        {
            if(s[i] == '2')
            {
               g[++cnt2] = i;
            }
        }
        if(cnt2 == 0) printf("0\n");
        else    printf("%d\n",dfs(1,0,m));
    }
}



总体来说这场不难,但是太久没写题,思维不太够用。掉分伤心。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值