首页 > 其他分享 >退背包简介 / NOI模拟 卖画

退背包简介 / NOI模拟 卖画

时间:2024-06-03 14:22:09浏览次数:18  
标签:背包 cus NOI int 简介 LL rd 卖画 id

退背包介绍

之前居然完全没了解过“退背包”,其实是个很易于接受的思路,看了下最简单的板子题居然是个黄题,离谱。

退背包的原理在于根据题意与状态设计,阶段顺序并不影响最终的答案,因此之前某个阶段的贡献是可以撤销的。

具体撤销的方法就是通过原先从 \(f_{i-1}\) 转移到 \(f_i\) 的状态转移方程进行代数推导推出由 \(f_i\) 转移到 \(f_{i-1}\) 的转移式。具体步骤不难,但要有“阶段是可以撤回的”这个意识,并且要分清楚什么时候是“阶段顺序不影响结果”什么时候是影响的。

通过下面这道题我们来感受一下退背包的思路与流程。

例题

涉及知识点:动态规划、回退背包

题意

有 \(n\ (\leq10^6)\) 个顾客,每个顾客要么买 \(x\in[1,a_i]\) 幅彩色画,要么买 \(y\in[1,b_i]\) 幅黑白画,要求至少有 \(C\ (\leq50)\) 个人买彩色画,求有多少种买画方案,对 \(10^9+7\) 取模。

思路

首先发现 \(C\) 非常小,突破点就在 \(C\)。我们反过来,将总共的购买方案数减去买了少于 \(C\) 幅彩色画的方案数,因此我们现在只需要求出后者。如果没有修改,DP 已经呼之欲出了。

设 \(f[i][j]\) 为第 \(i\) 个人,共有 \(j\) 个人买了彩色画的方案数,转移方程如下:

\[f[i][j]=f[i-1][j]*b_i+f[i-1][j-1]*a_{i} \]

怎么处理修改呢?我们会发现,由于其组合意义,把任何一个人当作最后一个人都可以,因此假设我们要删去某个人 \(p\) 的贡献:

\[f[i-1][j]=\frac{f[i][j]-f[i-1][j-1]*a_p}{b_p} \]

注意上式计算 \(f[i-1][j]\) 时用到了 \(f[i-1][j-1]\),那么 \(f[i-1][j-1]\) 又是怎么求出来的呢?

可以发现当 \(j=0\) 的时候,要删去某个人的贡献直接除以它的 \(b_i\) 即可,因此我们就算出来了 \(f[i-1][0]\),接着递推即可。

那么对于题目中的修改操作,我们就处理为先倒推撤销修改前那个人的贡献,再正推算出修改后那个人的贡献即可,修改一次的复杂度仅为 \(O(C)\),完全足够通过本题。

代码

#include<bits/stdc++.h>
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar __getchar
inline char __getchar(){
    static char ch[1<<20],*l,*r;
    return (l==r&&(r=(l=ch)+fread(ch,1,1<<20,stdin),l==r))?EOF:*l++;
}
#endif
template<class T>inline void rd(T &x){
    T res=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while('0'<=ch && ch<='9'){res=res*10+ch-'0';ch=getchar();}
    x=res*f;
}
template<class T>inline void wt(T x,char endch='\0'){
    static char wtbuff[20];
    static int wtptr;
    if(x==0){
        putchar('0');
    }
    else{
        if(x<0){x=-x;putchar('-');}
        wtptr=0;
        while(x){wtbuff[wtptr++]=x%10+'0';x/=10;}
        while(wtptr--) putchar(wtbuff[wtptr]);
    }
    if(endch!='\0') putchar(endch);
}
typedef long long LL;
typedef pair<int,int> pii;
const LL P=1e9+7;
const int MAXN=1e6+5,MAXC=55;
int n,c,q;
LL tot=1,f[MAXC];
pii cus[MAXN];
inline LL qpow(LL a,LL b=P-2){
    LL res=1;
    a%=P;
    while(b){
        if(b&1) res=res*a%P;
        a=a*a%P;
        b/=2;
    }
    return res;
}
int main(){
    // freopen("pic.in","r",stdin);
    // freopen("pic.out","w",stdout);
    rd(n);rd(c);
    for(int i=1;i<=n;i++) rd(cus[i].first);
    for(int i=1;i<=n;i++) rd(cus[i].second);
    f[0]=1;
    for(int i=1;i<=n;i++){
        tot=tot*(cus[i].first+cus[i].second)%P;
        for(int j=c-1;j>=0;j--){
            f[j]=(f[j]*cus[i].second%P + (j?f[j-1]*cus[i].first%P:0))%P;
        }
    }
    rd(q);
    int id,a,b;
    while(q--){
        rd(id);rd(a);rd(b);
        LL sum=0,invb=qpow(cus[id].second);

        tot=tot*qpow(cus[id].first+cus[id].second)%P;
        for(int i=0;i<c;i++){
            f[i]=(f[i] - (i?f[i-1]*cus[id].first%P:0) +P)%P*invb%P;
        }

        cus[id]=make_pair(a,b);

        tot=tot*(cus[id].first+cus[id].second)%P;
        for(int i=c-1;i>=0;i--){
            f[i]=(f[i]*cus[id].second%P + (i?f[i-1]*cus[id].first%P:0))%P;
        }

        for(int i=0;i<c;i++) sum=(sum+f[i])%P;
        wt((tot-sum+P)%P,'\n');
    }
    return 0;
}

标签:背包,cus,NOI,int,简介,LL,rd,卖画,id
From: https://www.cnblogs.com/SkyNet-PKN/p/18228819

相关文章

  • NOI模拟 捉迷藏
    涉及知识点:博弈论题意在一个树上,A和B可以通过边在节点间移动,每回合可以不移动,或者移动到有边直接连接的节点。A在抓B,当A与B处于同一个节点时即为被抓住,可以发现无论如何B最后都会被抓住,你需要添加最小数量的边使得B有策略可以永远不会被抓住。思路最终的必败态是......
  • 打卡信奥刷题(40)用Scratch图形化工具信奥B3828 [NOIP2008 普及组] [NICA #2] 优秀正整
    [NICA#2]优秀正整数题目描述Aya定义符合如下条件的正整数xxx为优秀正整数:x......
  • 2005NOIP普及组真题 4. 循环
    线上OJ:【05NOIP普及组】循环核心思想:高精度1、本题用到了标准的高精度乘法模板voidinit(inta[])//传入一个数组{strings;cin>>s;//读入字符串sa[0]=s.length();//用a[0]计算字符串s的位数for(i=1;i<=a[0];i++)a[i]=s[......
  • 第01章— 开篇词:cesium专栏简介和阅读建议
    引言Cesium.js作为一个强大且日益重要的地理空间信息可视化工具,其应用领域广泛却学习资料相对分散。我希望能够通过系统化、实战导向的教程,降低初学者的入门门槛,帮助读者快速掌握核心技能,同时为进阶开发者提供深层次的技术解析与优化策略。Cesium可以做什么?CesiumJs是一......
  • CSP历年复赛题-P1981 [NOIP2013 普及组] 表达式求值
    原题链接:https://www.luogu.com.cn/problem/P1981题意解读:中缀表达式求值,只有+,*,没有括号,保留后4位。解题思路:中缀表达式求值的典型应用,采用两个栈:符号栈、数字栈,对于没有括号的情况,只需要如下步骤:1、遍历表达式每一个字符2、如果遇到数字,则持续提取数字,保存整数到数字栈3、......
  • Solution Set before NOI2024
    前情提要:省选太唐没进队,现在是菜D。「ARC175E」ThreeViewDrawing原神。考虑令\(m\)为\(\sqrtk\)向上取整。那么有\(m^2-2m+1<k\lem^2\)。考虑一种能够覆盖某个视图一个角的做法,那么直接覆盖两个角,中间留一条缝,或是宽度为\(2\)的缝(这种情况下有可能有奇偶性的问题,但......
  • 【NOIP2018普及组复赛】题1:标题统计
    题1:标题统计题目描述凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符?注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字符数时,空格和换行符不计算在内。【输入格式】输入文件只有一行,一个字符串......
  • 智密腾讯云直播组建--客户端API简介
    客户端API指的是伴随着Demo提供的ZhimiTRTCLiveRoomSDK,常见于(工程目录/utils/ZhimiTRTCLiveRoom/sdk.js),并且以开放对象的方式重新包装一次对外开放,可参考(工程目录/utils/ZhimiTRTCLiveRoom/index.js),该包装方式主要是方便开发者扩展自己对应的功能,从而不必重复导入,导出等工作......
  • NOIP2024模拟赛10:热烈张扬
    NOIP2024模拟赛10:热烈张扬T1一句话题意:给定一颗树和两个玩家的起点\(a,b\)和各自的移动速度\(da,db\).问:如果二人均以最优策略移动,问最后谁是赢家(先走到对方当前位置)标签:LCA,思维,博弈不妨设\(a\)是速度快的,\(b\)是速度慢的。结论一:若二者初始距离\(\le\)先手......
  • 2021 NOIP
    廊桥分配1.错误想法:让当前飞机停到右端点最小的廊桥,但是当两个区间右端点都小于当前飞机左端点,选择最小的么?显然不是,应该选择序号最小的廊桥,这样不影响下一个飞机继续放置(左端点从小打到排序的)。这样,当只能有i个廊桥(枚举国内廊桥)的时候,也是可以取得最大值的。最后前缀和。错误......