131014 Regionals 2010, North America - Mid-Atlantic USA

H题:这题是一个变形的背包问题,注意两点:

1.数组开dp[2][],记录前一转态和后一个状态,否则超内存。

2.求最小值,这样能节省时间。

代码:

#include<iostream>
#include<cstdio>
#define maxn 1005
#define maxf 20005
#define INF 1000000
using namespace std;
int n,k,l,F;
int f[maxn],d[maxn];
int dp[2][maxf];
int DP()
{
    int ans=0;
    dp[0][0]=0;
    for(int i=1;i<=F;i++)
    {
        dp[0][i]=INF;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=F;j>=0;j--)
        {
            dp[1][j]=INF;
            //看第i个东西
            if(j-f[i]>=0&&dp[0][j-f[i]]+d[i]<=l)
            {
                dp[1][j]=min(dp[1][j],dp[0][j-f[i]]+d[i]);
            }
            //不看第i个东西
            if(dp[0][j]!=INF)
            dp[1][j]=min(dp[1][j],max(0,dp[0][j]-k));

            dp[0][j]=dp[1][j];
        }
    }
    for(int i=F;i>=0;i--)
    {
        if(dp[1][i]!=INF)
        {
            ans=i;
            break;
        }
    }
    return ans;
}
int main()
{
    while(scanf("%d%d%d",&n,&k,&l)!=EOF)
    {
        if(!n&&!k&&!l) break;
        F=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&f[i],&d[i]);
            F+=f[i];
        }
        printf("%d\n",DP());
    }
    return 0;
}
B题:这题是一个数位dp的题,主要是数位dp写的太少,基本上模式都一样。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1005
#define maxf 20005
#define INF 1000000
#define ll long long
using namespace std;
int k;
int bit[100],ans[100];
ll vis[100][100];
void init()
{
    ans[0]=-111;
    ans[1]=0;
    for(int i=2;i<=100;i++)
    {
        int x=i,cnt=0;
        while(x)
        {
            if(x%2)
            cnt++;
            x/=2;
        }
        ans[i]=ans[cnt]+1;
    }
}
//下标 前面1的个数 前一位是否取最高位 前面是否全是0 当前数是1
ll dfs(int p,int num,int a,int b,int c)
{
    if(p==0)
    {
        if(c==1) return k==0;
        else return ans[num]+1==k;
    }
    if(a==0&&vis[p][num]>=0)
    {
        return vis[p][num];
    }
    ll ret=0;
    int size=a?bit[p]:1;
    for(int i=0;i<=size;i++)
    {
        ret+=dfs(p-1,num+(i==1),a&&(i==size),b&&(i==0),b&&(i==1));
    }
    return a?ret:vis[p][num]=ret;
}
ll solve(ll x)
{
    if(x<=0) return 0;
    if(x==1) return k==0;
    int cnt=0;
    while(x)
    {
        bit[++cnt]=x%2;
        x/=2;
    }
    return dfs(cnt,0,1,1,0);
}
int main()
{
    ll l,r;
    init();
    while(scanf("%lld%lld%d",&l,&r,&k)!=EOF)
    {
        if(!l&&!r&&!k) break;
        memset(vis,-1,sizeof(vis));
        ll ret=solve(r)-solve(l-1);
        printf("%lld\n",ret);
    }
    return 0;
}


引用\[1\]:这段引用是一段C++代码,用于处理一个01序列的查询。代码中使用了前缀和和后缀和的思想,通过计算每个位置之前1的个数和之后1的个数,来处理查询区间内的操作。具体的实现细节可以参考代码注释。\[1\] 引用\[2\]:在处理多组询问时,为了不改变非连续1的计数,代码将区间分成两段处理。左半段都是1的情况单独处理,后半段第一个位置为0,可以通过前缀和相减来计算。这样可以保证在处理查询时不会影响到非连续1的计数。\[2\] 引用\[3\]:这段引用是对一个二进制循环序列的定义和问题描述。一个好的二进制循环序列是指通过一系列操作可以使其变为空序列。而一个二进制循环序列的美丽度被定义为使其变为好序列所需的最小修改次数。每次修改可以翻转序列中的任意一个元素,即0变为1,1变为0。给定一个长度为n的二进制字符串a和q个查询,每个查询给出两个整数li和ri,需要回答f(aliria\[li..ri\]),其中我们将子字符串aliria\[li..ri\]视为一个循环序列。\[3\] 问题: 请问这段代码的作用是什么? 回答: 这段代码的作用是处理一个01序列的查询。通过计算每个位置之前1的个数和之后1的个数,来处理查询区间内的操作。在处理多组询问时,为了不改变非连续1的计数,代码将区间分成两段处理,保证在处理查询时不会影响到非连续1的计数。最终输出每个查询区间的结果。\[1\]\[2\] #### 引用[.reference_title] - *1* *2* [ICPC22网络赛(1) - A 01 Sequence(前缀和,思维)](https://blog.csdn.net/Mr_dimple/article/details/126983251)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [The 2022 ICPC Asia Regionals Online Contest - A 01 Sequence](https://blog.csdn.net/qq_35339563/article/details/126959132)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值