Educational Codeforces Round 137 (Rated for Div. 2) 补D、E

Educational Codeforces Round 137 (Rated for Div. 2)(补D、E)

D:Problem with Random Tests暴力、数据随机:Mid

题意

给你一个0、1字符串,取两个子串并且对应的10进制数的或值最大,输出或运算后的二进制字符串。

数据随机:每一个位置上的1、0出现的概率均为1/2

思路

比赛时不知道数据随机有什么用,如果直接暴力感觉O(n2)就超时了

暴力:

  1. 为了使最后的数最大,就要使二进制字符串最长,于是其中一个字符串一定选:第一个1出现起的子串s1
  2. 为了使s1通过或运算变大,可以使s1的第一个0变为1的子串s2
  3. 于是暴力遍历s1的第一个1后面,第一个0前面的所有1(长度为s1.length-第一个0的位置)的字符串,求出或运算后的最大值

看似复杂度为O(n2),但是第一个1后面,第一个0前面所有的1的个数为50个的概率为(1/2)50(由于数据的随机性),所有最多遍历50下就可以确定答案了

ps:对于比较两个字符串表示的数的大小可以直接比较字符串的大小

代码

普通暴力
#include<bits/stdc++.h>
#define ll long long
using namespace std;

string del(string s){
    int i=0;
    while(s[i]=='0'&&i<s.length()-1)i++;
    return s.substr(i);
}

int main(){
    int n;
    string s;
    cin>>n>>s;
    s=del(s);
    int end=0;
    for(int i=0;i<s.length();i++){
        if(s[i]=='0'){
            end=i;
            break;
        }
    }
    string ans=s;
    for(int i=0;i<end;i++){
        string temp=s;
        for(int j=i;j<i+s.length()-end;j++){
            if(s[j]=='1')temp[j-i+end]='1';
        }
        ans=max(ans,temp);
    }
    cout<<ans<<endl;
}
利用bitset(可以进行位运算方便点)
#include<bits/stdc++.h>
#define ll long long
using namespace std;

string del(string s){
    int i=0;
    while(s[i]=='0'&&i<s.length()-1)i++;
    return s.substr(i);
}

int main(){
    int n;
    string s;
    cin>>n>>s;
    s=del(s);
    bitset<1000005>s1(s),s2(s);
    string ans=s1.to_string();
    for(int i=1;i<=50;i++){
        ans=max(ans,(s1|(s2>>i)).to_string());
    }
    cout<<del(ans)<<endl;
}

E:FTL动态规划:Hard–

题意

两个发射塔分别可以发射伤害为p1,p2的激光,但是充能时间分别t1,t2

其要攻击血量为h,防御力为s的敌方,总伤害为P的激光可以队敌方造成P-s的血量伤害。问最少需要多少时间击败对方

数据范围:

image-20221018185830224

思路

对于炮台,它有两种方式攻击:

  1. 只要有炮台充能好就发射
  2. 等两个炮台一起充能好发射

于是可以用dp来求解:dp[i]表示造成i伤害需要的最小时间,dp[i]可从以下方面取最小值

  1. 最后一次单独发射炮台1:dp[max(0,i-p1+s)]+t1
  2. 最后一次单独发射炮台2:dp[max(0,i-p2+s)]+t2
  3. 最后一次一起发射两炮台:这时需要考虑前面单独发射炮台的情况
    1. 假设一共发射了j次炮台1:
      1. j-1次单独发射炮台1:伤害贡献(j-1)*(p1-s)+(j*t1-t2)/t2*(p2-s)(前半部分是炮台1的单独发射的贡献,后半部分是这段时间炮台2单独发射的贡献)
      2. 最后一次同炮台2一起发射:伤害贡献p1+p2-s
      3. 时间花费dp[max(0,i-总伤害)+j*t1]
    2. 假设一共发射了j次炮台2:
      1. j-1次单独发射炮台2:伤害贡献(j-1)*(p2-s)+(j*t2-p1)/p1*(p1-s)(前半部分是炮台2的单独发射的贡献,后半部分是这段时间炮台1单独发射的贡献)
      2. 最后一次同炮台1一起发射:伤害贡献p1+p2-s
      3. 时间花费dp[max(0,i-总伤害)+j*t2]
    3. 关于在一起发射炮台前单独发射几次炮台(j的值),可以通过暴力的方式遍历,因为每个炮台最少可以造成1点伤害,于是for(j=0;j<=i;j++)遍历到i

代码

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

const int maxn=5005;
ll p1,t1,p2,t2,h,s;
ll dp[maxn];

int main(){
	cin>>p1>>t1>>p2>>t2>>h>>s;
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0;
	for(int i=1;i<=h;i++){
		dp[i]=min(dp[max(0ll,i-p1+s)]+t1,dp[max(0ll,i-p2+s)]+t2);
		for(int j=0;j<=i;j++){
			if(j*t1>=t2){
				ll x=(j-1)*(p1-s)+(j*t1-t2)/t2*(p2-s)+p1+p2-s;
				dp[i]=min(dp[i],dp[max(0ll,i-x)]+j*t1);
			}
			if(j*t2>=t1){
				ll x=(j-1)*(p2-s)+(j*t2-t1)/t1*(p1-s)+p1+p2-s;
				dp[i]=min(dp[i],dp[max(0ll,i-x)]+j*t2);
			}
		}
	}
	cout<<dp[h]<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值