P1941 飞扬的小鸟[NOIP2014提高组]
前50分显然是非常水的。甚至能用搜索过。
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
#define ll long long
#define pq priority_queue
#define mp make_pair
#define pii pair<int,int>
#define mod 998244353
#define debug(x) cerr<<#x<<"="<<x<<'\n'
int lowbit(int x) {return x&(-x);}
struct a {
int i,j,f,cnt;
};
a build(int aa,int b,int c,int d) {
a tmp;
tmp.i=aa,tmp.j=b,tmp.f=c,tmp.cnt=d;
return tmp;
}
const int maxn=22,maxm=19;
deque <a> q;
int n,m,k;
int l[maxn],r[maxn];
int x[maxn],y[maxn];
bool pipe[maxn];
int main(){
scanf("%d%d%d",&n,&m,&k);
for (int i=0;i<n;i++) {
scanf("%d%d",&x[i],&y[i]);
l[i]=0,r[i]=m+1;
}
for (int i=0;i<k;i++) {
int p;scanf("%d",&p);
pipe[p]=true;
scanf("%d%d",&l[p],&r[p]);
}
int ans=0,ans2=1e9;
for (int i=1;i<=m;i++) q.push_back(build(0,i,0,0));
while (!q.empty()) {
int i=q.front().i,j=q.front().j,f=q.front().f,cnt=q.front().cnt;
q.pop_front();
if (i==n) {
ans2=min(f,ans2);
continue;
}
if (j<=l[i]||j>=r[i]) continue;
if (pipe[i]) cnt++;
ans=max(ans,cnt);
if (f>=ans2) continue;
if (j-y[i]>0) q.push_front(build(i+1,j-y[i],f,cnt));
q.push_back(build(i+1,min(m,j+x[i]),f+1,cnt));
if (j+x[i]>=m) continue;
q.push_back(build(i+1,min(m,j+2*x[i]),f+2,cnt));
if (j+2*x[i]>=m) continue;
q.push_back(build(i+1,min(m,j+3*x[i]),f+3,cnt));
}
if (ans2==1e9) cout<<0<<endl<<ans<<endl;
else cout<<1<<endl<<ans2<<endl;
return 0;
}
这道题显然就是一道dp。状态也非常显然:
表示考虑到横坐标为i的位置高度为j的最小跳跃次数。转移分两种情况:
- 不跳,直接从前一个位置掉下来:
- 跳:枚举所有比j低且与j高度差为x[i-1] k倍(k为正整数)的高度h:
- 特别注意当j=m时需要特判
显然,第一种情况的转移是O(1)的,但第二种情况转移为O(m),那么总的复杂度为O(nm^2),只能得到70分。因此我们需要对第二种情况的转移进行优化。令g[i][j]为第二种情况的最小花费。
对于每一步转移时取min的值分为两个部分:f数组和k。可以发现g[i][j]在转移时用到的f数组只比g[i][j-x[i-1]]多一个f[i-1][j]+1,其他部分完全相同,而对于转移时用到的每一个相同的f数组,g[i][j]在转移时后面对应的k比g[i][j-x[i-1]]多1。因此
这样我们就将转移的复杂度降到了O(1)。
还是一定要注意j=m是的特判。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
#define ll long long
#define pq priority_queue
#define mp make_pair
#define pii pair<int,int>
#define mod 998244353
#define debug(x) cerr<<#x<<"="<<x<<'\n'
int lowbit(int x) {return x&(-x);}
int n,m,k;
const int maxn=1e4+10,maxm=1e3+10;
const int INF=1e9+11;
int x[maxn],y[maxn];
int f[maxn][maxm];
int g[maxm];
int l[maxn],r[maxn];
bool pipe[maxn];
int main(){
scanf("%d%d%d",&n,&m,&k);
for (int i=0;i<=n;i++) l[i]=0,r[i]=m+1;
for (int i=0;i<n;i++) scanf("%d%d",&x[i],&y[i]);
for (int i=0;i<k;i++) {
int p;
scanf("%d",&p);
pipe[p]=true;
scanf("%d%d",&l[p],&r[p]);
}
int cnt=0,ans=INF;
for (int i=0;i<=n;i++) {
for (int j=0;j<=m;j++) f[i][j]=(i==0?0:INF);
bool ok=false;
if (i) {
for (int j=1;j<=m;j++) {
if (j-x[i-1]>0) g[j]=min(f[i-1][j-x[i-1]],g[j-x[i-1]])+1;
else g[j]=INF;
if (j==m) {
for (int k=j;k>=max(0,j-x[i-1]);k--) {
g[j]=min(g[j],min(g[k],f[i-1][k])+1);
}
}
}
for (int j=l[i]+1;j<r[i];j++) {
if (j+y[i-1]<=m) f[i][j]=f[i-1][j+y[i-1]];
f[i][j]=min(f[i][j],g[j]);
if (f[i][j]!=INF) ok=true;
if (i==n) ans=min(ans,f[i][j]);
}
}
if (!ok&&i>0) {
break;
}
else if (pipe[i]) cnt++;
}
if (ans==INF) cout<<0<<endl<<cnt<<endl;
else cout<<1<<endl<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号