【BZOJ4583】购物(组合计数)
题意:商店出售3种颜色的球,分别为红、绿、蓝。
城市里有n个商店,第i个商店在第First_i天开始营业,连续营业Red_i+Green_i+Blue_i天,每个商店每天只能出售一种颜色的球。
每天最多有两个商店同时营业。如果同一天内有两个商店同时营业,那么这两个商店必须出售相同颜色的球。
求不同的出售方案数(对1,000,000,007取模)。两种方案不同,当且仅当某一天某一个商店出售的球的颜色不同。
1≤n≤50
1≤First_i≤500
0≤Red_i, Green_i, Blue_i≤100
0<Red_i + Green_i + Blue_i
First_i + Red_i + Green_i + Blue_i - 1≤500
保证每天最多有两个商店同时营业。
思路:WYZ作业 烦的一比 还是膜了本人的code才做出的
贴一下他的题解
我们很容易想到一个7维DP,dp[时间][店A剩余红球][店A剩余绿球][店A剩余蓝球][店B剩余红球][店B剩余绿球][店B剩余蓝球]
然后,首先我们发现,每个时刻一个店的剩余球总数是确定的,于是就可以把其中一个球的状态去掉,于是就变成5维了。
接着,我们尝试不记录其中一个店。
我们发现,如果某一段区间两个店同时开门,那么这段时间内卖掉的球一定是那个较早关门剩余的所有球。(因为较早关门的那个店一定要卖光,然后另一个店就必须跟着卖)
然后这段时间里的方案数,直接可以用组合数算出来。
于是我们就可以直接跳过有2个店开门的时间。
于是我们的DP状态就变成3维的了,空间&&时间都是500*100*100的。
O(1)转移xjb搞一搞就行了
1 const mo=1000000007; 2 var st,r,g,b:array[0..500]of longint; 3 dp,f:array[0..500,0..500]of int64; 4 c:array[0..500,-1..500]of int64; 5 now,sum,i,j,k,n,t:longint; 6 7 procedure swap(var x,y:longint); 8 var t:longint; 9 begin 10 t:=x; x:=y; y:=t; 11 end; 12 13 procedure qsort(l2,r2:longint); 14 var i,j,mid:longint; 15 begin 16 i:=l2; j:=r2; mid:=st[(l2+r2)>>1]; 17 repeat 18 while mid>st[i] do inc(i); 19 while mid<st[j] do dec(j); 20 if i<=j then 21 begin 22 swap(st[i],st[j]); 23 swap(r[i],r[j]); 24 swap(g[i],g[j]); 25 swap(b[i],b[j]); 26 inc(i); dec(j); 27 end; 28 until i>j; 29 if l2<j then qsort(l2,j); 30 if i<r2 then qsort(i,r2); 31 end; 32 33 function clac(x,y,z:longint):int64; 34 begin 35 clac:=c[x+y+z,x]*c[y+z,y] mod mo; 36 end; 37 38 function min(x,y:longint):longint; 39 begin 40 if x<y then exit(x); 41 exit(y); 42 end; 43 44 procedure solve(step:longint); 45 var i,j,k:longint; 46 begin 47 if step=0 then exit; 48 if sum=0 then 49 begin 50 now:=now+step; 51 exit; 52 end; 53 fillchar(f,sizeof(f),0); 54 for i:=0 to 100 do 55 for j:=0 to 100 do 56 begin 57 k:=sum-i-j; 58 if (k<0)or(k>100) then continue; 59 if i>0 then f[i-1,j]:=(f[i-1,j]+dp[i,j]) mod mo; 60 if j>0 then f[i,j-1]:=(f[i,j-1]+dp[i,j]) mod mo; 61 if k>0 then f[i,j]:=(f[i,j]+dp[i,j]) mod mo; 62 end; 63 for i:=0 to 100 do 64 for j:=0 to 100 do dp[i,j]:=f[i,j]; 65 inc(now); dec(sum); 66 solve(step-1); 67 end; 68 69 begin 70 assign(input,'bzoj4583.in'); reset(input); 71 assign(output,'bzoj4583.out'); rewrite(output); 72 readln(n); 73 for i:=1 to n do read(st[i]); 74 for i:=1 to n do read(r[i]); 75 for i:=1 to n do read(g[i]); 76 for i:=1 to n do read(b[i]); 77 c[0,0]:=1; 78 for i:=1 to 500 do 79 for j:=0 to i do c[i,j]:=(c[i-1,j-1]+c[i-1,j]) mod mo; 80 qsort(1,n); dp[0,0]:=1; 81 for t:=1 to n do 82 begin 83 solve(st[t]-now); 84 fillchar(f,sizeof(f),0); 85 if sum<=r[t]+g[t]+b[t] then 86 begin 87 for i:=0 to r[t] do 88 for j:=0 to g[t] do 89 begin 90 k:=sum-i-j; 91 if (k<0)or(k>b[t]) then continue; 92 f[r[t]-i,g[t]-j]:=(f[r[t]-i,g[t]-j]+dp[i,j]*clac(i,j,k)) mod mo; 93 end; 94 end 95 else 96 begin 97 for i:=r[t] to 100 do 98 for j:=g[t] to 100 do 99 begin 100 k:=sum-i-j; 101 if (k<b[t])or(k>100) then continue; 102 f[i-r[t],j-g[t]]:=(f[i-r[t],j-g[t]]+dp[i,j]*clac(r[t],g[t],b[t])) mod mo; 103 end; 104 end; 105 for i:=0 to 100 do 106 for j:=0 to 100 do dp[i,j]:=f[i,j]; 107 now:=now+min(sum,r[t]+g[t]+b[t]); 108 sum:=abs(r[t]+g[t]+b[t]-sum); 109 end; 110 solve(500); 111 writeln(dp[0,0]); 112 close(input); 113 close(output); 114 end.
null