zoukankan      html  css  js  c++  java
  • [loj3342]制作菜品

    当$n-1le m$,不妨令$d_{1}le d_{2}le...le d_{n}$,则$(n-1)kle mk=sum_{i=1}^{n}d_{i}le d_{1}+(n-1)d_{n}$
    将这个拆成两部分,即$(n-2)k+k$和$(n-2)d_{n}+(d_{1}+d_{n})$,由于后者大于等于前者,所以两项中必然有一项大于等于前者,容易发现一定存在$kle d_{1}+d_{n}$
    那么就可以不断贪心将$d_{1}$和$d_{n}$匹配,每一次必然会至少消除一个数,而最后一次因为总和恰好为$mk$所以必然全部消除
    当$m=n-2$,此时合法当且仅当存在一个集合$Ssubset {1,2,...,n}$使得$sum_{iin S}d_{i}=(|S|-1)k$
    证明:充分性,如果存在,将两部分分开处理,即有解且已构造得出
    必要性,可以证明若存在合法解,必然存在一组使得每次操作使至少一个点变为$0$(显然消除掉一定更优)
    构造:将每一个点向消除掉自己的点连无向边,显然这张图不存在大于2的环(考虑环上操作的先后顺序即可)
    因此即去除掉重边后,这张图是一棵森林且有至少2棵树(否则有$n-1$次操作),其中任意一棵子树即可作为集合$S$
    考虑怎么求出这个集合$S$,暴力$dp$令$f[i][j][k]$表示前$i$个点中选$j$个点和能否为$k$,复杂度为$o(n^{3}k)$无法通过
    如何使得其与$|S|$无关,即$S$需满足$sum_{iin S}d_{i}-k=-k$,同时权值范围仅变为$[-nk,nk]$,因此复杂度降为$o(n^{2}k)$
    问题即一个01背包的存在性判断,可以用$bitset$来优化,复杂度降为$o(frac{n^{2}k}{32})$,可以通过
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 505
     4 set<pair<int,int> >s;
     5 int t,n,m,k,d[N],vis[N];
     6 bitset<N*N*20>f[N];
     7 void work(int m){
     8     for(int i=1;i<=m;i++){
     9         int x=(*s.begin()).second;
    10         s.erase(s.begin());
    11         if (d[x]>=k){
    12             printf("%d %d",x,k);
    13             d[x]-=k;
    14             if (d[x])s.insert(make_pair(d[x],x));
    15         }
    16         else{
    17             int y=(*(--s.end())).second;
    18             s.erase(--s.end());
    19             printf("%d %d %d %d",x,d[x],y,k-d[x]);
    20             d[y]-=k-d[x];
    21             if (d[y])s.insert(make_pair(d[y],y));
    22             d[x]=0;
    23         }
    24         if (i!=m)printf("
    ");
    25     }
    26 }
    27 int main(){
    28     freopen("dish.in","r",stdin);
    29     freopen("dish.out","w",stdout);
    30     scanf("%d",&t);
    31     bool flag=0;
    32     while (t--){
    33         if (flag)printf("
    ");
    34         flag=1;
    35         scanf("%d%d%d",&n,&m,&k);
    36         for(int i=1;i<=n;i++)scanf("%d",&d[i]);
    37         if (n-1<=m){
    38             for(int i=1;i<=n;i++)s.insert(make_pair(d[i],i));
    39             work(m);
    40             continue;
    41         }
    42         memset(vis,0,sizeof(vis));
    43         for(int i=0;i<=n;i++)f[i].reset();
    44         f[0][n*k]=1;
    45         bool flagg=0;
    46         for(int i=1;i<=n;i++){
    47             f[i]=f[i-1];
    48             if (d[i]>=k)f[i]|=(f[i-1]<<d[i]-k);
    49             else f[i]|=(f[i-1]>>k-d[i]);
    50             if (f[i][(n-1)*k]){
    51                 flagg=1;
    52                 for(int j=i,t=(n-1)*k;j;j--)
    53                     if (f[j-1][t-(d[j]-k)]){
    54                         vis[j]=1;
    55                         t-=d[j]-k;
    56                     }
    57                 for(int j=1;j<=n;j++)
    58                     if (vis[j])s.insert(make_pair(d[j],j));
    59                 work(s.size()-1);
    60                 printf("
    ");
    61                 for(int j=1;j<=n;j++)
    62                     if (!vis[j])s.insert(make_pair(d[j],j));
    63                 work(s.size()-1);
    64                 break;
    65             }
    66         }
    67         if (!flagg)printf("-1");
    68     }
    69     return 0;
    70 }
    View Code
  • 相关阅读:
    把arguments转化成数组
    最小化重绘和重排
    选择器API
    事件委托
    WAhaha_hnu (zoj 2010 oct月赛)
    素数计数公式全面拉丁化改写小有改进Meissel公式梅塞尔Lehmer公式莱梅=勒梅尔筛法三种形式孟庆余公式(转载)
    NBUT 2013 Timed NOJ Training #005
    2013 腾讯马拉松初赛第一场
    hrboj 1683 树形DP
    哈尔滨2013校赛训练赛 4 解题思路
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13538353.html
Copyright © 2011-2022 走看看