有 \(n\) 堆石子,初始時第 \(i\) 堆石子有 \(a_i\) 個。dom
你每次取石子會取 \(k\) 個。在你取完一堆石子以後才能在下一堆中取石子。spa
遊戲會進行 \(t\) 輪,每輪會發生如下事件:code
每一堆式子有個上限 \(c_i\),若是在某個時刻,某堆石子的數量超過上限,就就輸了。遊戲
求在不會輸掉遊戲的前提下,你最少進行幾回取石子操做。事件
\(n,t\leq 200,1\leq k\leq {10}^9,0\leq a_i,b_i\leq c_i\leq {10}^9\)。get
咱們能夠在最後加一堆 \(a={10}^9,b={10}^9,c={10}^9\times (t+1)\) 的石子堆,這樣每次取石子都必定能取到 \(k\) 個。這可讓咱們更方便地計算石子個數。string
先考慮 \(a_i=0\) 的狀況。it
記 \(sa,sb\) 爲 \(a,b\) 的前綴和。io
記 \(f_{i,j}\) 爲前 \(i\) 堆石子,進行了 \(j\) 輪遊戲,且每次取石子都取了 \(k\) 個的最小操做次數。function
記 \(g_{i,j}\) 爲前 \(i\) 堆石子,進行了 \(j\) 輪遊戲,再取了若干次石子,每次石子都取了 \(k\) 個,且 \([1,i)\) 的石堆中沒有石子的最小操做次數。
若是不取第 \(i\) 種石子也知足要求(即 \(j\times b_i\leq c_i\) 且 \(f_{i-1,j} \neq \infty\)),轉移爲
不然枚舉最後一次取 \(i\) 的時間 \(l\),咱們的策略是:
所以,轉移爲:
時間複雜度爲 \(O(nt^2)\)。
\(a_i\neq 0\) 的狀況和 \(a_i=0\) 的狀況相似,只須要在某些計算石子個數的地方加上 \(a_i\) 便可。
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> #include<functional> #include<cmath> #include<vector> #include<assert.h> //using namespace std; using std::min; using std::max; using std::swap; using std::sort; using std::reverse; using std::random_shuffle; using std::lower_bound; using std::upper_bound; using std::unique; using std::vector; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ldb; typedef std::pair<int,int> pii; typedef std::pair<ll,ll> pll; void open(const char *s){ #ifndef ONLINE_JUDGE char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } void open2(const char *s){ #ifdef DEBUG char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;} void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');} int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;} int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;} void upmin(ll &a,ll b) { a=min(a,b); } const int N=210; const ll inf=0x3fffffffffffffffll; ll f[N][N][2]; ll g[N][N][2]; ll a[N],b[N],c[N],sa[N],sb[N]; ll ceil(ll a,ll b) { return (a+b-1)/b; } int n,t; ll k; int main() { open("c"); scanf("%d%d%lld",&n,&t,&k); for(int i=1;i<=n;i++) { scanf("%lld%lld%lld",&a[i],&b[i],&c[i]); sa[i]=sa[i-1]+a[i]; sb[i]=sb[i-1]+b[i]; } // printf("%lld\n",sa[n]); n++; a[n]=1000000000ll; b[n]=1000000000ll; c[n]=1000000000ll*(t+1); sa[n]=sa[n-1]+a[n]; sb[n]=sb[n-1]+b[n]; for(int i=1;i<=n;i++) for(int j=1;j<=t;j++) { f[i][j][0]=g[i][j][0]=inf; if(0*a[i]+j*b[i]<=c[i]&&f[i-1][j][0]!=inf) { upmin(f[i][j][0],f[i-1][j][0]); if(ceil(j*sb[i-1]+0*sa[i-1],k)*k<=0*sa[i]+j*sb[i]) upmin(g[i][j][0],ceil(j*sb[i-1]+0*sa[i-1],k)); } for(int l=1;l<j;l++) if(f[i-1][j-l][0]!=inf&&g[i][l][0]!=inf) { ll m=0*sa[i]+l*sb[i]-k*g[i][l][0]; ll x=ceil(max(0ll,m+(j-l)*b[i]-c[i]),k); if(__int128(k)*x>m) continue; upmin(f[i][j][0],g[i][l][0]+x+f[i-1][j-l][0]); if(ceil((j-l)*sb[i-1],k)*k<=m-x*k+(j-l)*sb[i]) upmin(g[i][j][0],g[i][l][0]+x+ceil((j-l)*sb[i-1],k)); } } for(int i=1;i<=n;i++) for(int j=0;j<=t;j++) { f[i][j][1]=g[i][j][1]=inf; if(1*a[i]+j*b[i]<=c[i]&&f[i-1][j][1]!=inf) { upmin(f[i][j][1],f[i-1][j][1]); if(ceil(j*sb[i-1]+1*sa[i-1],k)*k<=1*sa[i]+j*sb[i]) upmin(g[i][j][1],ceil(j*sb[i-1]+1*sa[i-1],k)); } for(int l=0;l<j;l++) if(f[i-1][j-l][0]!=inf&&g[i][l][1]!=inf) { ll m=1*sa[i]+l*sb[i]-k*g[i][l][1]; ll x=ceil(max(0ll,m+(j-l)*b[i]-c[i]),k); if(__int128(k)*x>m) continue; upmin(f[i][j][1],g[i][l][1]+x+f[i-1][j-l][0]); if(ceil((j-l)*sb[i-1],k)*k<=m-x*k+(j-l)*sb[i]) upmin(g[i][j][1],g[i][l][1]+x+ceil((j-l)*sb[i-1],k)); } } ll ans=f[n][t][1]; printf("%lld\n",ans); return 0; }