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


    [十二省联考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
    ");
    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
    ",ans);
    189 }
    190     return 0;
    191 }
  • 相关阅读:
    BigDecimal工具类处理精度计算
    Redis的简单使用和介绍
    数据库优化知识总结
    js弹出QQ对话框在线交谈
    火焰灯menu修改之后,可以实现数遍点击小方块停留在当前页面
    js作用域的一个小例子
    js中this的四种调用模式
    jquery火焰等效果导航菜单
    appserver配置虚拟主机
    一个类似百度文库选中弹出个小框的效果
  • 原文地址:https://www.cnblogs.com/rikurika/p/10692411.html
Copyright © 2020-2023  润新知