CodeForces - 1625C
题意: 一条马路,有n个限速牌,表示的是从这个限速牌开始到下一个限速牌或者到马路尾的这段距离的速度,你可以拆除其中k个限速牌,问最少的时间是多少。
题解: 线性问题,每个牌拆和不拆两种情况,开始考虑的贪心,但不会。
dp[i][j]表示的是到i这个点,一共拆除了j个限速牌。
可以根据限速牌数量写状态转移方程: dp[pos][j+pos-i-1]=min(dp[pos][j+pos-i-1],dp[i][j]+(a[pos]-a[i])*b[i]);
其中pos 和 i 是遍历的先后两个点,pos-i-1的意思是将pos 和 i中的牌子拆掉。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=505; const ll inf=1e18; ll a[N],b[N],dp[N][N]; ll vis[N],ans,sum[N]; ll n,m,k; signed main(){ cin>>n>>m>>k; for(ll i=1;i<=n;i++) cin>>a[i]; for(ll i=1;i<=n;i++) cin>>b[i]; a[n+1]=m; memset(dp,0x3f,sizeof(dp)); dp[1][0]=0; for(ll i=1;i<=n;i++) dp[i+1][0]=dp[i][0]+(a[i+1]-a[i])*b[i];//初始化,一个牌子不拆的情况下,到每一个点花费的时间 for(ll i=1;i<=n;i++) for(ll j=0;j<=k;j++) for(ll z=i+1;z<=n+1;z++){ dp[z][j+z-i-1]=min(dp[z][j+z-i-1],dp[i][j]+(a[z]-a[i])*b[i]); } ll ans=inf; for(ll i=0;i<=k;i++) ans=min(ans,dp[n+1][i]); cout<<ans<<endl; }