1.

[HNOI2001] 产品加工

一道简单的背包,然而我还是写了很久QAQ

时间范围是都小于5 显然考虑一维背包,dp[i]表示目前A消耗了i的最小B消耗

注意

if(b[i]) dp[j]=dp[j]+b[i];
 else dp[j]=1e9+7;

可以用B则直接转移,否则要把上一次的这个状态设为正无穷,只能用后两个转移。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=+;
const int N=*+;
int n,a[maxn],b[maxn],c[maxn],dp[N],lz[N],ans=1e9+;
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
memset(dp,,sizeof(dp));
dp[]=;
for(int i=;i<=n;i++)
for(int j=i*;j>=;j--){
if(b[i]) dp[j]=dp[j]+b[i];
else dp[j]=1e9+;//!!!!!!!!!!!!!!!!!!!!
if(a[i]&&j>=a[i]&&dp[j]>dp[j-a[i]]) dp[j]=dp[j-a[i]];
if(c[i]&&j>=c[i]&&dp[j]>dp[j-c[i]]+c[i]) dp[j]=dp[j-c[i]]+c[i];
if(i==n) ans=min(max(dp[j],j),ans);
}
cout<<ans;
return ;
}

2.

[HAOI2007]上升序列

看数据范围似乎是n^2可以过的,然而自己之前并不会写nlongn求最长上升子序列的算法就自己YY了一下,写得很丑,单调栈里从短到长从大到小,用了两个二分,一次找找最长的比它小的,一次找长度为它的位置是否可以更新。

这样找到以每个元素打头的最长上升序列,询问就从1到n跑一遍问它能不能到那么长,就保证了字典序最小。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
const int maxn=+;
int now,n,m,x,maxx,a[maxn],pre[maxn],dp[maxn],sta[maxn],sl=,sr;
int ef(int l,int r,int x){
int res=-;
while(l<=r){
int mid=(l+r)>>;
if(a[sta[mid]]>x) res=mid,l=mid+;
else r=mid-;
}
return res;
}
void ef2(int l,int r,int len,int x){
while(l<=r){
int mid=(l+r)>>;
if(dp[sta[mid]]==len) { if(a[sta[mid]]<=a[x]) sta[mid]=x; break;}
if(dp[sta[mid]]<len) l=mid+;
else if(dp[sta[mid]]>len) r=mid-;
}
}
void work() {
for(int i=n;i>=;i--) {
dp[i]=;
if(sl<=sr) {
now=ef(sl,sr,a[i]);
if(now!=-)
dp[i]=dp[sta[now]]+;
}
maxx=max(maxx,dp[i]);
while(sr>=sl&&dp[sta[sr]]<=dp[i]&&a[sta[sr]]<=a[i]) {
sr--;
}
if(sr<sl||dp[sta[sr]]<dp[i]) sta[++sr]=i;
else ef2(sl,sr,dp[i],i);
}
}
void query(int x){
if(x>maxx) puts("Impossible");
else {
int pre=;
for(int i=;i<=n;i++) {
if(dp[i]>=x&&a[i]>pre) {
pre=a[i];
if(x==)
printf("%d",a[i]);
else printf("%d ",a[i]);
x--;
if(!x) break;
}
}
printf("\n");
}
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
work();
scanf("%d",&m);
for(int i=;i<=m;i++) {
scanf("%d",&x);
query(x);
}
return ;
}

然而正确的nlogn求最长上升序列并不是这么写的,只用一个二分,不过在下并不是很清楚,懒得学以后再说吧。

从LLJ大佬那里学到了用线段树的做法,开一颗权值线段树,从后往前把Dp值存进去,每个点找它后面的最大Dp值来更新,感觉和正常的nlogn的思路可能差不多。

3.

UVA - 12063 Zeros and Ones

二进制数和它们的位模式对于计算机程序员来说总是非常有趣的。 在这个
您需要计算具有以下属性的正数二进制数的问题:
•数字正好是N位宽,它们没有前导零。
•一和零的频率相等。
•数字是K的倍数。
输入
输入文件包含几个测试用例。 输入的第一行为您提供了测试用例数,
T(1≤T≤100)。 那么T测试用例会跟随,每一行都在一行。 每个测试用例的输入包括
的两个整数,N(1≤N≤64)和K(0≤K≤100)。
产量
对于每组输入,首先打印测试用例编号。 然后打印二进制数的数字

谷歌翻译神坑,1和0频率相同翻译成0和0频率相同,喵喵喵?

把Case打成case被坑了一波。。对拍才发现QAQ

最好的做法是往后加0或者1 不用特判,不会炸整,往前加的话就要特判,然后注意开 long long ,要模两次保证不会炸 (LLJ大佬说要开usinged long long ,因为 long long 只到2^64-1,实际这题只到2^63所以不用)

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef unsigned long long LL;
const int maxn=;
const int maxk=;
int T,n,k;
LL dp[maxn][maxn][maxk],ans,ll=;
void work(){
if(!k||n&) {printf("0\n"); return;}
memset(dp,,sizeof(dp));
dp[][][]=;
for(int i=;i<=n;i++)
for(int j=;j<=i;j++)
for(int l=;l<k;l++) {
if(j) dp[i][j][(l+((ll=)<<(i-))%k)%k]+=dp[i-][j-][l];
if(i!=n) dp[i][j][l]+=dp[i-][j][l];
}
ans=;
printf("%llu\n",dp[n][n/][]);
}
int main()
{ scanf("%d",&T);
for(int i=;i<=T;i++){
scanf("%d%d",&n,&k);
printf("Case %d: ",i);
work();
}
return ;
}

这是往后加的版本

    for(int i=;i<n;i++)
for(int j=;j<=i;j++)
for(int l=;l<k;l++) {
dp[i+][j+][((l<<)|)%k]+=dp[i][j][l];
dp[i+][j][(l<<)%k]+=dp[i][j][l];
}

4.

UVA - 1628 Pizza Delivery

我爱记忆化搜索,记忆化搜索最强。

dp[i][j][o][k]表示i到j的订单已处理好,现在在i或者j 还要送k家的最优解

枚举,记忆化

for(int i=;i<l;i++) u=max(u,dfs(i,r,,k-)+e[i]-k*abs(p[i]-p[o==?l:r]));
for(int i=n;i>r;i--) u=max(u,dfs(l,i,,k-)+e[i]-k*abs(p[i]-p[o==?l:r]));

注意这一段先搜两边再中间,可以达到记忆化效果

代码

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=+;
int T,now,dp[maxn][maxn][][maxn],vis[maxn][maxn][][maxn],n,p[maxn],e[maxn],ans;
int dfs(int l,int r,int o,int k) {
if(k==) return ;
if(vis[l][r][o][k]==now) return dp[l][r][o][k];
vis[l][r][o][k]=now;
int &u=dp[l][r][o][k];
u=;
for(int i=;i<l;i++) u=max(u,dfs(i,r,,k-)+e[i]-k*abs(p[i]-p[o==?l:r]));
for(int i=n;i>r;i--) u=max(u,dfs(l,i,,k-)+e[i]-k*abs(p[i]-p[o==?l:r]));
return u;
}
int main()
{
scanf("%d",&T);
for(now=;now<=T;now++) {
ans=;
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&p[i]);
for(int i=;i<=n;i++) scanf("%d",&e[i]);
for(int kk=;kk<=n;kk++)
for(int i=;i<=n;i++)
ans=max(ans,dfs(i,i,,kk-)+e[i]-kk*abs(p[i]));
printf("%d\n",ans);
}
return ;
}

5.BZOJ 1009 [HNOI2008]GT考试

一开始傻逼地kmp直接往前跳一个就停了,后来改了又调了好久发现自己Kmp写错了,贼难受。。

就kmp转移然后矩阵优化。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
int ans,n,m,p,top,a[],nxt[],cnt[],vis[];
struct jz{
int x[][];
friend jz operator *(const jz&l,const jz&r){
jz res;
for(int i=;i<;i++)
for(int j=;j<;j++)
res.x[i][j]=;
for(int i=;i<;i++)
for(int j=;j<;j++) {
for(int k=;k<;k++)
(res.x[i][j]+=(l.x[i][k]*r.x[k][j])%p)%=p;
}
return res;
}
}base,ret,tmp;
void input() {
scanf("%d%d%d",&n,&m,&p);
char ch=getchar();
while(ch<''||ch>'') ch=getchar();
for(;ch>=''&&ch<='';ch=getchar()) a[++top]=ch-'';
}
int make_nxt(int a[],int *nxt) {
for (int j=,i=;i<=m;i++) {
while (j&&a[j+]!=a[i]) j=nxt[j];
if (a[j+]==a[i]) j++;
nxt[i]=j;
}
}
void ksm(int b){
while(b){
if(b&) ret=ret*base;
base=base*base;
b>>=;
}
}
void work() {
for(int i=;i<m;i++) {
cnt[i]++;
vis[a[i+]]=i+;
if(i+!=m) {base.x[i][i+]++;}
int tp=i;
while(nxt[tp]) {
tp=nxt[tp];
if(vis[a[tp+]]!=i+) {
vis[a[tp+]]=i+;
cnt[i]++;
base.x[i][tp+]++;
}
}
if(vis[a[]]!=i+) {
cnt[i]++;
base.x[i][]++;
}
base.x[i][]+=(-cnt[i]);
}
for(int i=;i<m;i++)
for(int j=;j<m;j++)
if(i==j) ret.x[i][j]=;
ksm(n);
ans=;
for(int i=;i<m;i++)
(ans+=ret.x[][i])%=p;
printf("%d\n",ans);
}
int main()
{
input();
make_nxt(a,nxt);
work();
return ;
}

GT考试

6.BZOJ 1855 [SCOI2010]股票交易

在某位学长的博客里看到这题第一句话是省选怎么会考这么简单的题呢,然后就发现自己不会做。。。

神奇的单调队列优化,可能是我单调队列写得太少了。。

很容易知道状态dp[i][j]表示时间为i手中股票为j的最大收益,初始化为极小值,dp[0][0]=0;

然后转移分三种

不买不卖:dp[i][j]=max(dp[i][j],dp[i-1][j]);

买入:dp[i][j]=max(dp[i][j],dp[i-w-1][j-k]-k*ap[i]);

卖出:dp[i][j]=max(dp[i][j],dp[i-w-1][j+k]+k*bp[i]);

然后我们发现后两个枚举k会超时,就把它优化一下 (其实我也。。比较懵逼)

买入:dp[i][j]=max(dp[i][j],dp[i-w-1][k]-(j-k)*ap[i]);

=max(dp[i][j],(dp[i-w-1][k]+k*ap[i])-j*ap[i]);

卖出:dp[i][j]=max(dp[i][j],dp[i-w-1][k]+(k-j)*bp[i]);

=max(dp[i][j],(dp[i-w-1][k]+k*ap[i])-j*bp[i]);

以买入为例,我们发现 这一部分 dp[i-w-1][k]+k*ap[i] (j-k>0,j-k<as[i])具有单调性,

k>j-as[i] 我们枚举k,然后丢进单调队列, 更新现在的dp[i][k];

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=+;
int ans,n,maxp,w,dp[maxn][maxn];
int ap[maxn],bp[maxn],as[maxn],bs[maxn],que[maxn],ql=,qr;
int main()
{
scanf("%d%d%d",&n,&maxp,&w);
for(int i=;i<=n;i++)
scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
memset(dp,,sizeof(dp));
dp[][]=;
for(int i=;i<=n;i++) {
ql=,qr=;
for(int j=;j<=maxp;j++) {
dp[i][j]=max(dp[i][j],dp[i-][j]);
if(i-w->) {
while(ql<=qr&&que[ql]<j-as[i]) ql++;
while(ql<=qr&&dp[i-w-][que[qr]]+que[qr]*ap[i]-j*ap[i]<=dp[i-w-][j]) qr--;
que[++qr]=j;
if(ql<=qr) dp[i][j]=max(dp[i][j],dp[i-w-][que[ql]]+que[ql]*ap[i]-j*ap[i]);
}
else if(j<=as[i]) dp[i][j]=max(dp[i][j],-ap[i]*j);
}
ql=,qr=;
for(int j=maxp;j>=;j--) {
if(i-w->){
while(ql<=qr&&que[ql]>j+bs[i]) ql++;
while(ql<=qr&&dp[i-w-][que[qr]]+que[qr]*bp[i]-j*bp[i]<=dp[i-w-][j]) qr--;
que[++qr]=j;
if(ql<=qr) dp[i][j]=max(dp[i][j],dp[i-w-][que[ql]]+que[ql]*bp[i]-j*bp[i]);
}
}
}
for(int i=;i<=maxp;i++) ans=max(ans,dp[n][i]);
printf("%d\n",ans);
return ;
}

股票交易

一些DP杂题的更多相关文章

  1. dp杂题(根据个人进度选更)

    ----19.7.30 今天又开了一个新专题,dp杂题,我依旧按照之前一样,这一个专题更在一起,根据个人进度选更题目; dp就是动态规划,本人认为,动态规划的核心就是dp状态的设立以及dp转移方程的推 ...

  2. 贪心/构造/DP 杂题选做Ⅱ

    由于换了台电脑,而我的贪心 & 构造能力依然很拉跨,所以决定再开一个坑( 前传: 贪心/构造/DP 杂题选做 u1s1 我预感还有Ⅲ(欸,这不是我在多项式Ⅱ中说过的原话吗) 24. P5912 ...

  3. 贪心/构造/DP 杂题选做Ⅲ

    颓!颓!颓!(bushi 前传: 贪心/构造/DP 杂题选做 贪心/构造/DP 杂题选做Ⅱ 51. CF758E Broken Tree 讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的 ...

  4. 专题:DP杂题1

    A POJ 1018 Communication System B POJ 1050 To the Max C POJ 1083 Moving Tables D POJ 1125 Stockbroke ...

  5. 【做题记录】DP 杂题

    P2577 [ZJOI2004]午餐 $\texttt{solution}$ 想到贪心: 吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序. 状态: \(f[i][j]\) 表示前 \(i\ ...

  6. 贪心/构造/DP 杂题选做

    本博客将会收录一些贪心/构造的我认为较有价值的题目,这样可以有效的避免日后碰到 P7115 或者 P7915 这样的题就束手无策进而垫底的情况/dk 某些题目虽然跟贪心关系不大,但是在 CF 上有个 ...

  7. DP杂题2

    1.邦邦的大合唱站队 https://www.luogu.org/problem/show?pid=3694 XY说这是道简单的签到题,然后我大概是普及组都拿不到三等的那种了.. 插入题解.写得太好了 ...

  8. 【模拟8.01】matrix(DP杂题,思维题)

    很神的题,感谢lnc大佬的指点. 先设1-LL[i]统称左区间,RR[i]-m为右区间 用L[i]统计从1-i列,出现的左区间端点的前缀和,R[i]是右区间.... f[i][j]中j表示当前在第i列 ...

  9. 正睿OI DAY3 杂题选讲

    正睿OI DAY3 杂题选讲 CodeChef MSTONES n个点,可以构造7条直线使得每个点都在直线上,找到一条直线使得上面的点最多 随机化算法,check到答案的概率为\(1/49\) \(n ...

随机推荐

  1. 原生js和jquery

    $(document).ready(function() {//jquery的写法 }); (function () { //原生js的写法 })();

  2. Python--模块之re

    re模块 就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的字节码,然后由用 C ...

  3. 理解webpack中的process.env.NODE_ENV

    参考资料 一. process 要理解 process.env.NODE_ENV 就必须要了解 process,process 是 node 的全局变量,并且 process 有 env 这个属性,但 ...

  4. 自己总结的CSS3中transform变换、transition过渡、animation动画的基本用法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  5. AcWing 215. 破译密码 (莫比乌斯反演)打卡

    达达正在破解一段密码,他需要回答很多类似的问题: 对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d. 作为达达的同学,达达希望得到你的帮助. ...

  6. haproxy笔记

    haproxy安装.启动.日志配置 方法1:#安装 yum install haproxy -y #日志配置 sed -i 's/^#$ModLoad imudp/$ModLoad imudp/g' ...

  7. NIO浅析(一)

    一:NIO与IO的区别 1.NIO面对的是缓冲区,IO面对的是流 2.NIO是非阻塞的,IO是阻塞的 3.NIO中引入了选择器 二:既然NIO面对的是缓冲区,那就先来了解缓冲区 1.NIO中Buffe ...

  8. python中输入多个数字(代码实现)

    不多说,直接上代码: list1 = [] #定义一个空列表 str1 = input("请输入数值,用空格隔开:") # list2 = str1.split(" &q ...

  9. PAT_A1037#Magic Coupon

    Source: PAT A1037 Magic Coupon (25 分) Description: The magic shop in Mars is offering some magic cou ...

  10. A1082 Read Number in Chinese (25 分)

    1082 Read Number in Chinese (25 分)   Given an integer with no more than 9 digits, you are supposed t ...