Codeforces Round #461

本文解析了五道经典编程题目,包括玩具复制、魔法森林、洞穴绘画、机器人吸尘器及捕鸟问题,涵盖了数学逻辑、贪心算法、动态规划等核心概念。

A. Cloning Toys
题意:初始时有一个原版玩具,使用一个原版玩具可以制造出一个原版玩具和一个复制玩具,使用一个复制玩具可以制造出两个复制玩具。问能否得到特定数目的原版和复制玩具。
题解:a个原版b个复制,直接判断,注意特判情况a为0时b必为1、b为1时a必为0。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#include<iomanip>
#define maxn 300050
#define maxm 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
const double pi=acos(-1.0);
using namespace std;
typedef long long ll;
typedef long double ld;

int a,b;
int main()
{
    scanf("%d%d",&a,&b);
    if(b==0||(a==0&&b!=1))
    {
        printf("No\n");
        return 0;
    }
    if(b==1&&a!=0)
    {
        printf("No\n");
        return 0;
    }
    a-=(b-1);
    if(a<0||a%2==1)printf("No\n");
    else printf("Yes\n");
    return 0;
}

B. Magic Forest
题意:在1-n的范围内找三元组(a,b,c)要求为三角形的三边长且三个数的异或值为0,求满足条件的三元组的个数。
题解:根据异或的性质,a^b^c=0即a^b=c,O(n^2)枚举即可解决。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#include<iomanip>
#define maxn 300050
#define maxm 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
const double pi=acos(-1.0);
using namespace std;
typedef long long ll;
typedef long double ld;

int n;

int main()
{
    scanf("%d",&n);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
        {
            int t=i^j;
            if(t>=j&&t<=n&&t<i+j&&t>j-i)
                ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

C. Cave Painting
题意:给出n和k,判断n除以1-k中每一个数的余数是否各不相同。
题解:n除以1的余数必然为0,那么要满足题目的条件,n除以2的余数只能为1,依此类推,n除以i的余数只能为i-1。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#include<iomanip>
#define maxn 300050
#define maxm 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
const double pi=acos(-1.0);
using namespace std;
typedef long long ll;
typedef long double ld;

ll a,b;

int main()
{
    scanf("%I64d%I64d",&a,&b);
    for(ll i=2;i<=b;i++)
    {
        if(a%i!=i-1)
        {
            printf("NO\n");
            return 0;
        }
    }
    printf("YES\n");
    return 0;
}

D. Robot Vacuum Cleaner
题意:给定一系列只由s和h组成的字符串,求一个字符串的排列使得总串中子序列sh的数目最多。
题解:贪心,将字符串按照s所占比重从大到小排列即可。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#include<iomanip>
#define maxn 100050
#define maxm 1000050
#define INF 0x3f3f3f3f
#define eps 1e-8
const double pi=acos(-1.0);
using namespace std;
typedef long long ll;
typedef long double ld;

int n;
struct node
{
    string s;
    double t;
}e[maxn];
bool cmp(node a,node b)
{
    return a.t>b.t;
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        cin>>e[i].s;
        int num=e[i].s.length();
        int a=0;
        for(int j=0;j<num;j++)
        {
            if(e[i].s[j]=='s')a++;
            e[i].t=1.0*a/num;
        }
    }
    sort(e,e+n,cmp);
    int num=0,p;
    ll ans=0;
    for(int i=0;i<n;i++)
    {
        p=e[i].s.length();
        for(int j=0;j<p;j++)
        {
            if(e[i].s[j]=='s')
                num++;
            else ans+=num;
        }
    }
    printf("%I64d\n",ans);
    return 0;
}

E. Birds
题意:n棵树上各有ci只鸟,现在从第1棵树开始,在第i棵树上每捉一只鸟需要花费vi法力值。不论在哪棵树上,每捉一只鸟法力值上限会增加b。每换一棵树法力值会增加x,初始时法力值及其上限均为w。求最多能捉到的鸟的数目。
题解:这是一个容量不定的多重背包。dp的第一维显然是树的数目,但给出的法力值较大,不适合作为第二维。这里第二维为捉住的鸟数,dp[i][j]为走过i棵树抓了j只鸟剩下的最大法力值,最终只需要找出dp[i]中值存在的最大j值即可。状态转移方程为:
dp[i][j]=max(dp[i][j],dp[i-1][j-k]-k*v[i])
此外每一次枚举完鸟的数目以后需要增加法力值以及更新容量。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#include<iomanip>
#define maxn 1050
#define INF 0x3f3f3f3f
#define eps 1e-8
const double pi=acos(-1.0);
using namespace std;
typedef long long ll;
typedef long double ld;

ll n,w,b,x;
ll c[maxn],v[maxn];
ll dp[maxn][maxn*10];

ll Max(ll a,ll b){return a>b?a:b;}
ll Min(ll a,ll b){return a<b?a:b;}

int main()
{
    scanf("%I64d%I64d%I64d%I64d",&n,&w,&b,&x);
    for(int i=1;i<=n;i++)scanf("%I64d",&c[i]);
    for(int i=1;i<=n;i++)scanf("%I64d",&v[i]);
    memset(dp,-1,sizeof(dp));
    dp[0][0]=w;
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
        sum+=c[i];
        ll cnt=w;
        for(int j=0;j<=sum;j++)
        {
            for(int k=0;k<=c[i];k++)
            {
                if(k>j)break;
                if(dp[i-1][j-k]==-1)continue;
                if(dp[i-1][j-k]<k*v[i])continue;
                dp[i][j]=Max(dp[i][j],dp[i-1][j-k]-k*v[i]);
            }
            if(dp[i][j]!=-1)dp[i][j]=Min(dp[i][j]+x,cnt);
            cnt+=b;
        }
    }
    for(ll i=sum;i>=0;i--)
    {
        if(dp[n][i]!=-1)
        {
            printf("%I64d\n",i);
            return 0;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值