BestCoder Round #92【map,枚举,DP】

1001  Skip the Class  

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

对于每个课程只需要存储它的最大的两个翘课价值-.-

课程名需要map 成 int ,方便储存  -.-


代码:

#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
int shu[120][2];
void slove()
{
    int a,n,b=1,c;
    map<string,int> ma;
    int ll=0;
    string ch;
    scanf("%d",&n);
    memset(shu,0,sizeof(shu));
    for (int i=0;i<n;i++)
    {
        cin>>ch>>a;
        if (ma[ch])
        {
            c=ma[ch];
            if (a>shu[c][0])
            {
                shu[c][0]=a;
                if (shu[c][0]>shu[c][1])
                {
                    a=shu[c][1];
                    shu[c][1]=shu[c][0];
                    shu[c][0]=a;
                }
            }
        }
        else
        {
            ma[ch]=b++;
            c=ma[ch];
            if (a>shu[c][0])
            {
                shu[c][0]=a;
                if (shu[c][0]>shu[c][1])
                {
                    a=shu[c][1];
                    shu[c][1]=shu[c][0];
                    shu[c][0]=a;
                }
            }
        }
    }
    int ans=0;
    for (int i=0;i<=b;i++)
        ans+=shu[i][0]+shu[i][1];
    printf("%d\n",ans);
}
int main()
{
    int t;scanf("%d",&t);
    for (int i=0;i<t;i++)
        slove();
    return 0;
}



1002 Count the Sheep

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 -  C - D

我们可以考虑 A 为 男生  --最后将 ABCD 可以直接翻转为 DCBA  (女生开始)

然后考虑  A - B   ——   C - D 

B为女,C 为男,  当B 和 C 有 关系时才成立,  所以会有一个A=C的, 同理也有一个B=D的

然后我们只需要考虑中间那个边是哪一条边所连接的就行了,

先储存一下每个男生女生所在的边数、然后依次枚举中间那条边即可。


代码:

#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define LL __int64
int n,m,k;
LL shu1[100100],shu2[100100];
int x[100100],y[100100];
void slove()
{
    int a,b;
    scanf("%d%d%d",&n,&m,&k);
    memset(shu1,0,sizeof(shu1));
    memset(shu2,0,sizeof(shu2));
    for (int i=0;i<k;i++)
    {
        scanf("%d%d",&a,&b);
        shu1[a]++;shu2[b]++;
        x[i]=a;y[i]=b;
    }
    LL ans=0;
    for (int i=0;i<k;i++)
    {
        a=x[i];b=y[i];
        ans+=(shu1[a]-1)*(shu2[b]-1);
    }
    printf("%I64d\n",ans*2);
}
int main()
{
    int t;scanf("%d",&t);
    for (int i=0;i<t;i++)
        slove();
    return 0;
}



1003  Girls Love 233

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

用 dp[i][j][k]  第i个2在j处剩余k智商  所得到的  233 串 

统计2的个数和位置,

然后从左向右枚举每一个2的位置----

最后最大值即可。

在枚举过程中要保证 i 的位置在 i-1 的后面。


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char ch[102];
int ll,n,m,ans;
int dp[102][102][52];// dp[i][j][k]  第i个2在j处剩余k智商  所得到的  233 串 
int wei[102];
void slove()
{
    scanf("%d%d",&n,&m);
    m/=2;
    scanf("%s",ch+1);ll=0;
    for (int i=1;i<=n;i++)
        if (ch[i]=='2') 
            wei[++ll]=i;
    //printf("%s    %d\n",ch+1,ll);
    if (ll==0||ll>n-2)
        printf("0\n");
    else
    {
        ans=0;
        int cost;
        for (int i=1;i<=ll;i++)
        for (int j=1;j<=n;j++)
        for (int k=0;k<=m;k++)
        dp[i][j][k]=-1;
        //cout<<dp[2][4][0]<<endl;
        //  cout<<m<<endl;
        for (int i=1;i<=ll;i++)
        {
            for (int j=max(1,wei[i]-m);j<=min(wei[i]+m,n);j++)
            {
                cost=abs(wei[i]-j);
                if (i==1)
                    dp[i][j][m-cost]=0;
                else
                {
                    for (int jj=i-1;jj<j;jj++)
                    {
                        for (int kk=m;kk>=cost;kk--)
                        {
                            if (dp[i-1][jj][kk]!=-1)
                            {
                                if (jj+2<j)
                                    dp[i][j][kk-cost]=max(dp[i][j][kk-cost],dp[i-1][jj][kk]+1);
                                else
                                    dp[i][j][kk-cost]=max(dp[i][j][kk-cost],dp[i-1][jj][kk]);
                                //     printf("%d    %d   %d  %d   %d\n",i,j,kk-cost,kk,cost);
                            }
                        }
                    }
                }
            }
        }
        for (cost=0;cost<=m;cost++)
        {
            for (int i=ll;i<=n;i++)
            {
                if (dp[ll][i][cost]!=-1)
                {
                    //   printf("%d ------   %d   %d %d\n",dp[ll][i][cost],ll,i,cost);
                    ans=max(ans,dp[ll][i][cost]+(i+1<n));
                }
            }
        }
        printf("%d\n",ans);
    }
}
int main()
{
    int t;scanf("%d",&t);
    while (t--)
        slove();
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值