题目链接
A-古老的牛市,遗迹的天梯
做法:n只有200,简单dp,设dp[i]为到达i这个位置时的最小步数。
转移方程:j+k 从j+k这个点倒退k步然后一步到i
for(int j=i-1;j>=1;--j){
for(int k=0;k=a[i]){
p[i]=min(dp[i],dp[j+k]+k+1);
flag=1;
}
}
#pragma GCC optimize(2)
#include
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=2e2+10;
ll a[N],dp[N],f[N];
int n;
int main()
{
f[0]=1;rep(i,1,40) f[i]=f[i-1]*2;
n=read(); rep(i,1,n) a[i]=read(),dp[i]=1e14;
dp[1]=0;
for(int i=2;i<=n;++i){
int flag=0;
for(int j=i-1;j>=1;--j){
for(int k=0;k=a[i]){
dp[i]=min(dp[i],dp[j+k]+k+1);
flag=1;
}
}
}
if(!flag) {puts("-1");return 0;}
}
printf("%d\n",dp[n]);
}
/*
5
0 1 2 3 100
*/
B--几乎毁灭牛市的流星雨
做法:记录每个格子的陨石到达时间,简单bfs一下就可以了。
#pragma GCC optimize(2)
#include
#define ll long long
#define maxn 1005
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=3e2+10,inf=0x3f3f3f3f;
int vs[N][N],m;
int dir[4][2]={1,0,0,1,-1,0,0,-1};
struct node
{
int x,y,t;
};
int main()
{
m=read();
memset(vs,inf,sizeof(vs));
while(m--)
{
int x=read(),y=read(),t=read();
vs[x][y]=min(vs[x][y],t);
rep(i,0,3)
{
int xx=x+dir[i][0],yy=y+dir[i][1];
if(xx<0||yy<0||xx>300||yy>300) continue;
vs[xx][yy]=min(vs[xx][yy],t);
}
}
queueque;
que.push({0,0,0});
while(que.size()){
node now=que.front();que.pop();
//printf("x:%d y:%d t:%d\n",now.x,now.y,now.t);
if(vs[now.x][now.y]==inf) {
printf("%d\n",now.t);return 0;
}
rep(i,0,3)
{
int xx=now.x+dir[i][0],yy=now.y+dir[i][1];
if(xx<0||yy<0||xx>300||yy>300) continue;
if(vs[xx][yy]<=now.t+1)continue;
que.push({xx,yy,now.t+1});
}
}
}
C-迁徙过程中的河流
做法:经典两人坐船过河问题。就两种方案过河:
三个人的时候 a、b、c无论怎么过 最优都是a+b+c
四个人以上,每次运输完,保持左边至少有三个以上,且a、b在左边
假设a、b、y、z 从小到大排序 a是最小,b是大于a 那么就是:
ay a az a
ab a yz b
两个方案中取最小的就可以了。
#include
using namespace std;
int n;
int a[100010];
int cal(int a, int b, int y, int z)
{
return min(z + a + y + a, b + a + z+b);
}
void solve()
{
int sum=0;
int i=n-1;
while(i>2)
{
int m=cal(a[0],a[1],a[i-1],a[i]);
sum+=m;
i-=2;
}
if (i==2)
sum += a[0] + a[1] + a[2];
else
sum += a[1];
printf("%d\n", sum);
}
int main()
{
cin>>n;
for(int i=0;i>a[i];
sort(a,a+n);
if(n==1) cout<
E-牛牛的旅游纪念品
做法:三维dp ,dp[i][j][k] k==0||k==1 代表第i位数取或者不取,且已经取了j个数时的最大权值。
预处理:
dp[0][0][0]=dp[0][0][1]=0; for(int i=1;i<=k;++i) dp[i][1][1]=a[i];
状态转移方程:
rep(i,1,n) { for(int j=min(i,m);j>=0;--j){ dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]); dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][1]); if(i-k>=0&&j-1>=0){ dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][0]+a[i]); dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][1]+a[i]); } } }
代码:
#pragma GCC optimize(2)
#include
#define ll long long
#define maxn 1005
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=1e4+10,M=1e2+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n,m,k;
ll dp[N][M][2];
int a[N];
int main()
{
n=read(),m=read(),k=read();
rep(i,1,n) a[i]=read();
memset(dp,-inf,sizeof(dp));
dp[0][0][0]=dp[0][0][1]=0;
for(int i=1;i<=k;++i) dp[i][1][1]=a[i];
rep(i,1,n)
{
for(int j=min(i,m);j>=0;--j){
dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]);
dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][1]);
if(i-k>=0&&j-1>=0){
dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][0]+a[i]);
dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][1]+a[i]);
}
}
}
printf("%lld\n",max(dp[n][m][0],dp[n][m][1]));
//printf("%lld %lld\n",dp[n][m][0],dp[n][m][1]);
}
/*
4 2 2
-2 -4 6 -1
*/