2050 Programming Competition 部分题解

1005. 球赛

因为傻逼错误导致绝杀失败,还没开放补题,先把代码放着,等开放了再试试能不能切(能切)

update:能补题了,不过wa了,对不起广大网友,我继续修改。

继续update:才发现思路没问题,不过我贴的代码细节写错了,总算过了这题,Yes!

我的思路是(不一定对,现在对了!!!,之前写了个背包复杂度400*t*n超时了,换成二进制没来得及debug):假设在第 i 位最多能打完d[ i ]场比赛,那么从第 i +1 位开始计分,设A得分的集合为S,假设从 i+1 到 j-1 A可以得1分或者3分,表示二进制就是1010,假设s[ j ] = 'A',那么A的得分就变成10100,s[ j ] = 'B',A的得分集合不变,s[ j ] = '?',那么A的得分就是1010 | 10100 = 11110,我们往后面枚举20次得分,如果在第 j 位,S&(1<<11)或者S&(1<<(j-i-11))不为0,表示当前可以结束一场比赛,那么更新d[ j ]=max(d[ j ], d[ i ]+1 ),算完20次得分后,如果能打成平局即S&(1<<10)不为0,那么我们继续往后每两次得分的去枚举,这个就很简单留给你来解决了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=10005,inf=1e8;
int d[maxn];
char s[maxn];
void up(int& x,int y)
{
	if(x<y)x=y;
}
int ok(char a,char b)
{
	if(a=='?'||b=='?')return 2;
	if(a==b)return 1;
	return 0;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int ans=0;
		scanf("%s",s+1);
		int n=strlen(s+1);
		for(int i=1;i<=n;i++)d[i]=-inf;
		for(int i=0;i<=n-11;i++)
		if(d[i]>=0)
		{
			int s1=1;
			for(int j=i+1;j<=n&&j-i<=20;j++)
			{
				int s2=(s1<<1);
				if(s[j]=='A')
				s1=s2;
				else if(s[j]=='?')
				s1|=s2;
				if(s1&(1<<11))
				{
					
					up(d[j],d[i]+1);
					//printf("i=%d j=%d d[j]=%d\n",i,j,d[j]);
					s1^=(1<<11);
				}
				if(j-i>=11)
				{
					int t=(1<<(j-i-11));
					if(s1&t)
					{
						up(d[j],d[i]+1);
						s1^=t;						
					}

				}
			}
			int flag=1,mark=0;
			if(!(s1&(1<<10)))flag=0;
			
			if(flag)
			for(int j=i+22;j-i<=50;j+=2)
			{
				int tmp=ok(s[j],s[j-1]);
				if(tmp)
				{
					mark=1;
					up(d[j],d[i]+1);
					if(tmp==1)
					break;
				}
			}
			if(flag&&!mark)
			up(d[i+22],d[i]);
		}
		for(int i=11;i<=n;i++)
		up(ans,d[i]);
		printf("%d\n",ans);
	}
}
/*
212
????????????????????ABABABABABABABABABABABABABABABABABABABABA
*/

1006. 冰水挑战

设d[ i ][ j ]为前 i 个挑战中完成了 j 个挑战所能得到的最大体力值,对于第 i+1 个挑战,我可以选择不挑战,那么d[ i+1][ j ]=max(d[i+1][ j ], d[ i ][ j]),选择挑战,那么d[ i+1 ][ j+1 ]=max(d[ i+1 ][ j+1 ],min(d[ i ][ j ], bi) - ai + ci ) (必须要min(d[ i ][ j ], bi) - ai > 0 才行)。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1005;
ll inf=1e18;
ll d[2][maxn];
void up(ll& x,ll y)
{
    x=max(x,y);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,a,b,c,cur=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        d[cur][i]=0;
        d[cur][0]=m;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            cur=!cur;
            for(int j=0;j<=n;j++)d[cur][j]=0;
            for(int j=0;j<=n;j++)
            if(d[!cur][j]!=0)
            {
                int t=min(1ll*b,d[!cur][j]);
                if(t>a) 
                up(d[cur][j+1],t-a+c);
                up(d[cur][j],d[!cur][j]+c);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        if(d[cur][i])
        ans=i;
        printf("%d\n",ans);
    }
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值