思路:
很显然给出的点可以构成一棵树,设dp[i][j]表示走到i个走廊剩余j时间还能够拿的画的最大数量。
当i为叶子节点(展室)时,直接求数量即可;当i为非叶子节点时,枚举分给左子树的时间k,那么
dp[i][j]=max(dp[i<<1][k]+dp[i<<1|1][time]);
要注意要减去穿过走廊所用的时间,因为是来回,所以要* 2 ,可以在读入的时候就*2;
要记得读入的时候按照dfs的顺序读入。
还有就是根据题意“警察赶来之前”,也就是说第s秒是不算的,要s=s-1;
代码:
///#pragma GCC optimize(3) ///#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline") ///#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll>PLL; typedef pair<int,int>PII; typedef pair<double,double>PDD; #define I_int ll inline ll read() { ll x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } char F[200]; inline void out(I_int x) { if (x == 0) return (void) (putchar('0')); I_int tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(F[--cnt]); //cout<<" "; } ll ksm(ll a,ll b,ll p) { ll res=1; while(b) { if(b&1)res=res*a%p; a=a*a%p; b>>=1; } return res; } const int inf=0x3f3f3f3f,mod=1000000007; const ll INF = 0x3f3f3f3f3f3f3f3f; const int maxn=1e6+7,maxm=3e5+7,N=1e6+7; const double PI = atan(1.0)*4; struct node{ int time,val; }a[maxn]; int dp[1100][1100]; void dfs(int u){ a[u].time=read(),a[u].val=read(); a[u].time*=2; if(a[u].val==0){ dfs(u<<1);dfs(u<<1|1); } } void dfs1(int u,int s){ if(s==0||dp[u][s]) return ;///没时间或是已经被记录过 if(!a[u].val){ for(int k=0;k<=s-a[u].time;k++){///注意边界时间 要减去通过走廊的时间 dfs1(u<<1,k);dfs1(u<<1|1,s-k-a[u].time); dp[u][s]=max(dp[u][s],dp[u<<1][k]+dp[u<<1|1][s-k-a[u].time]); } } else{//画室 dp[u][s]=min(a[u].val,(s-a[u].time)/5); } } int main() { int s=read();s--; dfs(1); dfs1(1,s); out(dp[1][s]); return 0; }
参考:题解