[十二省联考2019]皮配(分类讨论的动态规划)

OI考场上正解爆零和不会有什么区别。    --鲁迅

可惜咱连正解都想不到

难得连着部分分加爆搜混了60分

结果

忘清一个数组

$60$->$10$

我枯了

讲解开始

①:有20分爆搜

②:首先考虑k=0的情况

经过简单推理发现:

每个城市选择阵营和每个学校选择派系互不干扰

对于选阵营和选派系各自做一个01背包dp

结果就是二者的合理方案数相乘

③:其次考虑有k的情况

除了“有下属学校有偏好的城市”和“有偏好的学校”以外

其他的学校/城市依然可以按照上面k=0的方法进行背包dp

它们和被偏好限制的城市/学校互不影响

此后考虑对k个偏好的处理

k只有30个,而与此同时...
$s_i$$\leq$ $min$$($$10,M$$)$...

学校人数小于等于10!

这时方程已经出来了

dp[i][0/1][o][p]

对于前i个被限制的学校,该学校加入了0/1阵营,此时这些学校中加入了d0的有o人,这些学校所属的城市中加入了c0的有多少人

两种dp的结果的合理方案相乘的加和就是答案

时间复杂度 $O(c*M+n*M+k*(10*k)*M)$

详见代码(领略下精神就好哈)

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 using std::sort;
  5 typedef long long lint;
  6 const lint mo=998244353;
  7 template<typename st> st max(st a,st b){return a>b?a:b;}
  8 template<typename st> st min(st a,st b){return a<b?a:b;}
  9 int T,n,c,c0,c1,d0,d1;
 10 const int N=1011;
 11 const int M=2511;
 12 struct school
 13 {
 14     int cnt,ct,dis;
 15     bool friend operator < (school a,school b)
 16     {
 17         if((a.dis!=-1)^(b.dis!=-1)) return(a.dis!=-1)>(b.dis!=-1);
 18         return a.ct<b.ct;
 19     }
 20 }sc[N];
 21 struct city
 22 {
 23     int cnt,dis,dcnt;
 24 }ct[N];
 25 int sum,sum2;
 26 
 27 lint dp1[M],dp2[M];
 28 lint dp[33][2][331][M];
 29 
 30 
 31 int k;
 32 
 33 void memclr()
 34 {
 35     memset(dp1,0,sizeof(dp1));
 36     memset(dp2,0,sizeof(dp2));
 37     dp1[0]=dp2[0]=1;
 38     sum=0;
 39     dp[0][0][0][0]=1;
 40     sum2=0;
 41     n=c0=c=c1=d0=d1=k=0;
 42 }
 43 
 44 void add(lint &vv,int u,int i,int o,int p)
 45 {
 46     if(o<0||p<0) return;
 47     vv=(vv+dp[u][i][o][p])%mo;
 48 }
 49 lint fuck1(int l,int r)
 50 {
 51     return l>r?0:(l<=0?dp1[r]:(dp1[r]-dp1[l-1]+mo)%mo);
 52 }
 53 lint fuck2(int l,int r)
 54 {
 55     return l>r?0:(l<=0?dp2[r]:(dp2[r]-dp2[l-1]+mo)%mo);
 56 }
 57 
 58 int main()
 59 {
 60 scanf("%d",&T);
 61 while(T--)
 62 {
 63     memclr();
 64     scanf("%d%d",&n,&c);
 65     scanf("%d%d%d%d",&c0,&c1,&d0,&d1);
 66     for(int i=0;i<=c;i++) ct[i].cnt=ct[i].dis=ct[i].dcnt=0;
 67     for(int i=1;i<=n;i++)
 68     {
 69         scanf("%d%d",&sc[i].ct,&sc[i].cnt);
 70         ct[sc[i].ct].cnt+=sc[i].cnt;
 71         sum+=sc[i].cnt;
 72         sc[i].dis=-1;
 73     }
 74     scanf("%d",&k);
 75     for(int i=1,xin;i<=k;i++)
 76     {
 77         scanf("%d",&xin);
 78         scanf("%d",&sc[xin].dis);
 79         ct[sc[xin].ct].dis=1;
 80         ct[sc[xin].ct].dcnt+=sc[xin].cnt;
 81         sum2+=sc[xin].cnt;
 82     }
 83     sort(sc+1,sc+1+n);
 84     for(int i=1;i<=n;i++)//对于没有偏好限制的学校的背包dp 
 85     {
 86         if(sc[i].dis!=-1) continue;
 87         for(int j=d0-sc[i].cnt;j>=0;j--)
 88         {
 89             dp1[j+sc[i].cnt]=(dp1[j+sc[i].cnt]+dp1[j])%mo;
 90         }
 91     }
 92     for(int i=1;i<=c;i++)//对于没有偏好限制的城市的背包dp 
 93     {
 94         if(ct[i].dis||ct[i].cnt==0) continue;
 95         for(int j=c0-ct[i].cnt;j>=0;j--)
 96         {
 97             dp2[j+ct[i].cnt]=(dp2[j+ct[i].cnt]+dp2[j])%mo;
 98         }
 99     }
100     for(int i=1;i<=d0;i++) dp1[i]=(dp1[i]+dp1[i-1])%mo;//前缀和 
101     for(int i=1;i<=c0;i++) dp2[i]=(dp2[i]+dp2[i-1])%mo;//前缀和 
102     for(int i=1;i<=k;i++)//分类讨论对于k个有偏好学校的dp 
103     {
104         for(int j=0;j<=1;j++)
105         {
106             for(int o=sum2;o>=0;o--)
107             {
108                 for(int p=c0;p>=0;p--)
109                 {
110                     dp[i][j][o][p]=0;
111                     switch(j)
112                     {
113                         case 0:
114                         {
115                             if(sc[i].dis!=0)
116                             {
117                                 if(sc[i].ct==sc[i-1].ct)
118                                 {
119                                     add(dp[i][j][o][p],i-1,j,o-sc[i].cnt,p);
120                                 }else
121                                 {
122                                     add(dp[i][j][o][p],i-1,j,o-sc[i].cnt,p-ct[sc[i].ct].cnt);
123                                     add(dp[i][j][o][p],i-1,j^1,o-sc[i].cnt,p-ct[sc[i].ct].cnt);
124                                 }
125                             }
126                             if(sc[i].dis!=1)
127                             {
128                                 if(sc[i].ct==sc[i-1].ct)
129                                 {
130                                     add(dp[i][j][o][p],i-1,j,o,p);
131                                 }else
132                                 {
133                                     add(dp[i][j][o][p],i-1,j,o,p-ct[sc[i].ct].cnt);
134                                     add(dp[i][j][o][p],i-1,j^1,o,p-ct[sc[i].ct].cnt);
135                                 }
136                             }
137                             break;
138                         }
139                         case 1:
140                         {
141                             if(sc[i].dis!=2)
142                             {
143                                 if(sc[i].ct==sc[i-1].ct)
144                                 {
145                                     add(dp[i][j][o][p],i-1,j,o-sc[i].cnt,p);
146                                 }else
147                                 {
148                                     add(dp[i][j][o][p],i-1,j,o-sc[i].cnt,p);
149                                     add(dp[i][j][o][p],i-1,j^1,o-sc[i].cnt,p);
150                                 }
151                             }
152                             if(sc[i].dis!=3)
153                             {
154                                 if(sc[i].ct==sc[i-1].ct)
155                                 {
156                                     add(dp[i][j][o][p],i-1,j,o,p);
157                                 }else
158                                 {
159                                     add(dp[i][j][o][p],i-1,j,o,p);
160                                     add(dp[i][j][o][p],i-1,j^1,o,p);
161                                 }
162                             }
163                             break;
164                         }
165                     }
166                 }
167             }
168         }
169     }
170     int mic=sum-c1,mid=sum-d1;
171     if(mic>c0||mid>d0)
172     {
173         printf("0\n");
174         continue;
175     }
176     lint ans=0;
177     for(int i=0;i<=c0;i++)
178     {
179         for(int j=0;j<=sum2;j++)
180         {
181             lint vv=(dp[k][0][j][i]+dp[k][1][j][i])%mo;
182             if(vv)
183             {
184                 ans=(ans+vv*((fuck1(mid-j,d0-j)*fuck2(mic-i,c0-i))%mo)%mo)%mo;//将合理方案相乘后加给答案 
185             }
186         }
187     }
188     printf("%lld\n",ans);
189 }
190     return 0;
191 }

猜你喜欢

转载自www.cnblogs.com/rikurika/p/12_Province_d2t1.html
今日推荐