zoukankan      html  css  js  c++  java
  • 【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.
     

     

  • 相关阅读:
    【学习笔记】最小表示法
    bzoj1912【Apio2010】patrol 巡逻
    hdu1057
    hdu1056
    hdu1055
    hdu1054
    hdu1053
    hdu1052
    hdu1051
    hdu1050
  • 原文地址:https://www.cnblogs.com/myx12345/p/6554717.html
Copyright © 2011-2022 走看看