寒假Day3
一、动态规划
1.小a和uim之大逃离
题目描述
瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液。怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任一个格子结束。开始时小a用魔瓶吸收地面上的魔液,下一步由uim吸收,如此交替下去,并且要求最后一步必须由uim吸收。魔瓶只有k的容量,也就是说,如果装了k+1那么魔瓶会被清空成零,如果装了k+2就只剩下1,依次类推。怪物还说道,最后谁的魔瓶装的魔液多,谁就能活下来。小a和uim感情深厚,情同手足,怎能忍心让小伙伴离自己而去呢?沉默片刻,小a灵机一动,如果他俩的魔瓶中魔液一样多,不就都能活下来了吗?小a和他的小伙伴都笑呆了!
现在他想知道他们都能活下来有多少种方法。
一个整数,表示方法数。由于可能很大,输出对1 000 000 007取余后的结果。
f[i][j][p][q]表示他们走到(i,j),且两人魔瓶内魔液量的差为p时的方法数。q=0表示最后一步是小a走的,q=1表示最后一步是uim走的。题目中说魔瓶的容量为k,实际上就是动归时p需要对k+1取余数,即p只有0~k,k+1种可能。答案为所有f[i][j][0][1]的和。
动归方程如下:(为了方便已经令k=k+1)
f[i][j][p][0]+=f[i-1][j][(p-mapp[i][j]+k)%k][1] (i-1>=1)
f[i][j][p][0]+=f[i][j-1][(p-mapp[i][j]+k)%k][1] (j-1>=1)
f[i][j][p][1]+=f[i-1][j][(p+mapp[i][j])%k][0] (i-1>=1)
f[i][j][p][1]+=f[i][j-1][(p+mapp[i][j])%k][0] (j-1>=1)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int h=0;h<K;h++){
if(i+1<=n){
f[i+1][j][(h+a[i+1][j])%K][0]=(f[i+1][j][(h+a[i+1][j])%K][0]+f[i][j][h][1])%Mod;
f[i+1][j][(h-a[i+1][j]+K)%K][1]=(f[i+1][j][(h-a[i+1][j]+K)%K][1]+f[i][j][h][0])%Mod;
}
if(j+1<=m){
f[i][j+1][(h+a[i][j+1])%K][0]=(f[i][j+1][(h+a[i][j+1])%K][0]+f[i][j][h][1])%Mod;
f[i][j+1][(h-a[i][j+1]+K)%K][1]=(f[i][j+1][(h-a[i][j+1]+K)%K][1]+f[i][j][h][0])%Mod;
}
if(h==0)ans=(ans+f[i][j][h][1])%Mod;
}
- 赛斯石
题目描述
现需上市Need Need Need 赛斯重量的赛斯石,卖家想算出这些赛斯石经过某种合并方式来获得的最大收益。然而目前有一个问题,市场在真程大殿附近(真程海洋中心位置),卖家需要租船送赛斯石过去(即不考虑卖家自己租船过去的费用),目前有十种船可以租,载重量从1si 1si 1si 到10si 10si 10si ,每艘船的租价也是有所不同的,如下表所示:
由于真程大殿附近有强烈的赛斯力,导致无法对赛斯石进行任何操作,商家将赛斯石运过来之后就只能按照之前合并好的卖。假设卖家不返回,且这些赛斯石全部能卖出去。现在卖家他要计算总盈利(设总盈利=赛斯石的总收益-租船所需总费用),请你设计一个程序,算出一种最佳方案,以获得最大总盈利。
for(int i=1;i<=t;i++)
for(int j=1;j<=10;j++)
if(i-j>=1)
solution[i]=max(solution[i],solution[i-j]+solution[j]);
if(t<=10)
cout<<solution[t]+1;
else cout<<solution[t];
3 .猫狗大战
题目描述
新一年度的猫狗大战通过SC(星际争霸)这款经典的游戏来较量,野猫和飞狗这对冤家为此已经准备好久了,为了使战争更有难度和戏剧性,双方约定只能选择Terran(人族)并且只能造机枪兵。
比赛开始了,很快,野猫已经攒足几队机枪兵,试探性的发动进攻;然而,飞狗的机枪兵个数也已经不少了。野猫和飞狗的兵在飞狗的家门口相遇了,于是,便有一场腥风血雨和阵阵惨叫声。由于是在飞狗的家门口,飞狗的兵补给会很快,野猫看敌不过,决定撤退。这时飞狗的兵力也不足够多,所以没追出来。
由于不允许造医生,机枪兵没办法补血。受伤的兵只好忍了。555-
现在,野猫又攒足了足够的兵力,决定发起第二次进攻。为了使这次进攻给狗狗造成更大的打击,野猫决定把现有的兵分成两部分,从两路进攻。由于有些兵在第一次战斗中受伤了,为了使两部分的兵实力平均些,分的规则是这样的:1)两部分兵的个数最多只能差一个;2)每部分兵的血值总和必须要尽可能接近。现在请你编写一个程序,给定野猫现在有的兵的个数以及每个兵的血格值,求出野猫按上述规则分成两部分后每部分兵的血值总和。
用一个Bool类型的DP
dp[i][j][k] i表示第一对的血量总数j第二对的血量总数k表示相差人数。
只有两种选择要么被一对选要么对二队选
dp[0][0][0]=1;
for(i=1;i<=n;i++){
scanf("%d",&h[i]);
sum+=h[i];
for(p=sum-h[i];p>=0;p--)
for(k=10;k>=0;k--){
s=sum-h[i]-p;
if(dp[p][s][k]){
dp[p+h[i]][s][k+1]=1;
if(k>0)
dp[p][s+h[i]][k-1]=1;
else
dp[s+h[i]][p][1]=1;
}
}
}
4.不等式数列
不等式序列 将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,
有多少个排列恰好有k个“<”。答案对2015取模。 注:1~n的排列指的是1~n这n个数各出现且仅出现一次的数列。
#include<bits/stdc++.h>
#define Mod 2015
using namespace std;
int n,k;
int dp[1500][1500];
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)
dp[i][0]=dp[i][i-1]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=min(i-1,k);j++){
dp[i][j]=(dp[i-1][j-1]*(i-j)+dp[i-1][j]*(j+1))%Mod;
}
cout<<dp[n][k]<<endl;
return 0;
}
dp[i][j]表式前i个数j个减号的方案数
当排列插入原数列时,当插入的位置是j+1的位置时减号的个数不需要加可以保持原数,还有i-j的位置时减号的个数需要+1
所以可以得出状态转移方程 dp[i][j]=(dp[i-1][j-1](i-j)+dp[i-1][j](j+1))%Mod;
5.经营与开发
4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以“EX”为开头的英语单词。
eXplore(探索) eXpand(拓张与发展) eXploit(经营与开发) eXterminate(征服) ——维基百科
今次我们着重考虑exploit部分,并将其模型简化: 你驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过n个星球。
星球笼统的分为2类:资源型和维修型。(p为钻头当前能力值)
1. 资源型:含矿物质量a[i],若选择开采,则得到a[i]p的金钱,之后钻头损耗k%,即p=p(1-0.01k)
2. 维修型:维护费用b[i],若选择维修,则支付b[i]p的金钱,之后钻头修复c%,即p=p(1+0.01c)
注:维修后钻头的能力值可以超过初始值(你可以认为是翻修+升级) 请作为舰长的你仔细抉择以最大化收入。 【输入格式】 第一行4个整数n,k,c,w。 以下n行,每行2个整数type,x。 type为1则代表其为资源型星球,x为其矿物质含量a[i];
type为2则代表其为维修型星球,x为其维护费用b[i]; 【输出格式】 一个实数(保留2位小数),表示最大的收入。
k=1-0.01*k;c=1+0.01*c;
for(int i=1;i<=n;i++) scanf("%d%d",&t[i],&a[i]);
for(int i=n;i;i--)
if (t[i]==1)
ans=max(ans,ans*k+a[i]);
else
ans=max(ans,ans*c-a[i]);
printf("%.2lf\n",ans*w);
正难则反,F[i]表示第i–n个星球的最优收入,且假设从第i个星球开始时钻头能力为1。换句话说,这样的状态设计,规定了一个参考系。
转移过程就变得简单:如果在第i个星球开采,那么第i+1–n个星球的初始钻头能力就是1*(1-0.01k)。换句话说,就是F[i+1]*(1-0.01k)。
所以F[i]=max{F[i+1],F[i+1]*(1-0.01k)+a[i]}
对于维护型星球,大同小异。就系数和代价的正负而已。
观察方程,F[i]=max{F[i+1],F[i+1]*(1-0.01k)+a[i]}
实际上就是取下i+1–n的最值而已,所以这题实际上就成了贪心。
6.Treasure Chest
贝西和伯尼找到了一个装满了金币的宝箱!但是,作为奶牛,他们不能随便进入一家商店去买东西。所以他们决定去用这些金币玩一个游戏。
这里有N(1<=N<=5000)个硬币,每个都有一个价值C_i(1<=C_i<=5000)。这些硬币被摆成了一行。贝西和伯尼每人一回合。到了一只奶牛的回合时,他就要拿走最左边或者最右边的硬币。当没有硬币时,游戏结束。
贝西和伯尼都想要使自己拿到的金币价值尽量高,贝西先拿。现在贝西想要你帮帮她,算出她最多可以拿多少钱(伯尼也会尽量取到最优)。
for(int i=1;i<=n;i++){
cin>>c[i];
H[i]+=H[i-1]+c[i];
dp[i][i]=c[i];
}
for(int i=n-1;i>=1;i--)
for(int j=i+1;j<=n;j++){
dp[i][j]=max(H[j]-H[i-1]-dp[i+1][j],H[j]-H[i-1]-dp[i][j-1]);
}
cout<<dp[1][n];
dp[i][j]表示i和j之间的最大值
7.新魔法药水
题目描述
商店里有N种药水,每种药水都有一个售价和回收价。小S攒了V元钱,还会M种魔法,可以把一些药水合成另一种药水。他一天可以使用K次魔法,问他一天最多赚多少钱?
输入输出格式
输入格式:
第一行四个数N、M、V、K
接下来N行,每行两个数,表示药水的售价和回收价。
接下来M行,每行若干个数,第一个数表示魔法的成品,第二个数是原料的种数,接下来为各种原料的编号
输出格式:
一个数,表示小S的最大利润
巨火恶心题DP和dwq想了一晚上都没有想出来
还正在思考
#include<cstdio>
#define int long long
const int N=65,M=245,V=1005,K=35,inf=1e9;
int dp[K][V];//dp[i][j] means the max dollars we can get after using i times magic ans j dollars.
int method[N][M][N],cme[N][M],ccme[N];
int now[N][M][N],cn[N][M],ccn[N];
int in[N],out[N];
int n,m,vv,k;
int v[N],w[N];
inline void copp()
{
int i,j,k;
for(i=1;i<=n;i++)
{
ccn[i]=ccme[i];
for(j=1;j<=ccn[i];j++)
{
cn[i][j]=cme[i][j];
for(k=0;k<=cn[i][j];k++)
now[i][j][k]=method[i][j][k];
}
}
return;
}
signed main()
{
int i,j,l,a,sum;
scanf("%lld%lld%lld%lld",&n,&m,&vv,&k);
for(i=1;i<=n;i++)
scanf("%lld%lld",&in[i],&out[i]);
for(i=1;i<=m;i++)
{
sum=0;
scanf("%lld",&a);
ccme[a]++;
scanf("%lld",&cme[a][ccme[a]]);
for(j=1;j<=cme[a][ccme[a]];j++)
scanf("%lld",&method[a][ccme[a]][j]),sum+=in[method[a][ccme[a]][j]];
method[a][ccme[a]][0]=sum;
}
copp();
int cishu=1,mn,jmn;
for(i=1;i<=n;i++)
{
mn=inf;
for(j=1;j<=ccme[i];j++)
if(method[i][j][0]<mn)
mn=method[i][j][0],jmn=j;
v[i]=mn;
w[i]=out[i]-mn;
}
for(i=1;i<=k;i++)
for(j=1;j<=n;j++)
for(l=vv;l>=v[j];l--)
if(dp[i][l]<dp[i-cishu][l-v[j]]+w[j])
dp[i][l]=dp[i-cishu][l-v[j]]+w[j];
int mx,jmx[10];
bool flag=0;
for(cishu++;cishu<=m;cishu++)
{
for(i=1;i<=n;i++)
{
mx=0;flag=0;
for(j=1;j<=ccn[i];j++)
{
for(l=1;l<=cn[i][j];l++)
{
for(int jxc=1;jxc<=ccme[now[i][j][l]];jxc++)
if(mx<in[now[i][j][l]]-method[now[i][j][l]][jxc][0])
mx=in[now[i][j][l]]-method[now[i][j][l]][jxc][0],jmx[0]=now[i][j][l],jmx[1]=jxc,flag=1,jmx[2]=j,jmx[3]=l;
}
}
if(!flag)
{
v[i]=inf;
w[i]=-inf;
continue;
}
now[i][jmx[2]][0]-=mx;
now[i][jmx[2]][jmx[3]]=method[jmx[0]][jmx[1]][1];
for(int lsk=2;lsk<=cme[jmx[0]][jmx[1]];lsk++)
now[i][jmx[2]][++cn[i][jmx[2]]]=method[jmx[0]][jmx[1]][lsk];
v[i]=now[i][jmx[2]][0];
w[i]=out[i]-v[i];
}
for(i=cishu;i<=k;i++)
for(j=1;j<=n;j++)
for(l=vv;l>=v[j];l--)
if(dp[i][l]<dp[i-cishu][l-v[j]]+w[j])
dp[i][l]=dp[i-cishu][l-v[j]]+w[j];
}
printf("%lld\n",dp[k][vv]);
return 0;
}