[loj3331]选课
考虑$P=0$,由于$T-\sum_{i=1}^{m}s_{i}\le 40$,因此一个第$i$个分类中最多得到$s_{i}+42$的学分,可以对每一类分别背包
暴力背包复杂度为$o(n^{2})$,但背包实际用到的部分只有$o(40)$个位置,因此考虑直接求某个体积的答案
先枚举$3$的个数,那么问题相当于求体积为$\{1,2\}$的答案,可以将相邻两个1看作一个2来贪心,预处理出两类的前缀和,再对体积的奇偶性分类讨论
时间复杂度:预处理$o(n\log n+40n)$,合并$o(40^{2}m)$
当$P=12$,先对与$P$无关的分类按上述方式处理,那么剩下的问题就有$m\le 12$
对于这些分类,先求出所有没有限制的课程的结果(注意这里的范围要到$[s_{i}-36,s_{i}+42]$),然后$o(2^{P})$暴力枚举这些课程是否选择,复杂度$o(2^{P}40^{2}m+76n)$
有两个小问题:1.有一组数据不满足$T\ge \sum_{i=1}^{m}s_{i}$,因此差值需要对0取min;2.最终的和有可能超过$\sum_{i=1}^{m}s_{i}+42$,但下标不能太大(否则复杂度不对),将下标对$T-\sum_{i=1}^{m}s_{i}$取min即可
View Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 50004 4 #define oo 0x3f3f3f3f 5 map<int,int>mat[N]; 6 map<int,int>::iterator it; 7 vector<int>vo,ve,w[N],c[N],v[N][4]; 8 int V,n,m,x,y,ans,a[N],s[N],vis[105],p[105],sum[105][105],g[105],f[105],ff[105][105],dp[105]; 9 void init(int k){ 10 vo.clear(); 11 for(int i=0;i+1<v[k][1].size();i+=2)vo.push_back(v[k][1][i]+v[k][1][i+1]); 12 for(int i=0;i<v[k][2].size();i++)vo.push_back(v[k][2][i]); 13 sort(vo.begin(),vo.end()); 14 for(int i=0;i+1<vo.size();i++)vo[i+1]+=vo[i]; 15 ve.clear(); 16 for(int i=1;i+1<v[k][1].size();i+=2)ve.push_back(v[k][1][i]+v[k][1][i+1]); 17 for(int i=0;i<v[k][2].size();i++)ve.push_back(v[k][2][i]); 18 sort(ve.begin(),ve.end()); 19 for(int i=0;i+1<ve.size();i++)ve[i+1]+=ve[i]; 20 } 21 int query_12(int k,int x){ 22 if (x<0)return oo; 23 if (x%2==0){ 24 if (x==0)return 0; 25 if (vo.size()<x/2)return oo; 26 return vo[x/2-1]; 27 } 28 if (!v[k][1].size())return oo; 29 if (x==1)return v[k][1][0]; 30 if (ve.size()<x/2)return oo; 31 return ve[x/2-1]+v[k][1][0]; 32 } 33 int query_123(int k,int x){ 34 int s=0,ans=query_12(k,x); 35 for(int i=0;i<v[k][3].size();i++){ 36 s+=v[k][3][i]; 37 ans=min(ans,s+query_12(k,x-3*(i+1))); 38 } 39 return ans; 40 } 41 void merge(){ 42 memset(ff[0],oo,sizeof(ff[0])); 43 for(int i=0;i<=42;i++) 44 for(int j=0;j<=42;j++)ff[0][min(i+j,s[0])]=min(ff[0][min(i+j,s[0])],f[i]+dp[j]); 45 memcpy(dp,ff[0],sizeof(dp)); 46 } 47 void dfs(int k){ 48 if (k>V){ 49 int tot=0; 50 for(int i=1;i<=V;i++) 51 for(int j=1;j<=V;j++) 52 if ((vis[i])&&(vis[j])){ 53 if (sum[i][j]==oo)return; 54 tot+=sum[i][j]; 55 } 56 for(int i=1;i<=p[0];i++) 57 for(it=mat[p[i]].begin();it!=mat[p[i]].end();it++) 58 if (vis[(*it).second])tot+=c[p[i]][(*it).first]; 59 memcpy(dp,g,sizeof(g)); 60 for(int i=1;i<=p[0];i++){ 61 int ss=0; 62 for(it=mat[p[i]].begin();it!=mat[p[i]].end();it++) 63 if (vis[(*it).second])ss+=w[p[i]][(*it).first]; 64 for(int j=0;j<=42;j++)f[j]=ff[i][j+36-ss]; 65 merge(); 66 } 67 for(int i=s[0];i<=42;i++)ans=min(ans,tot+dp[i]); 68 return; 69 } 70 vis[k]=0; 71 dfs(k+1); 72 vis[k]=1; 73 dfs(k+1); 74 } 75 int main(){ 76 scanf("%d%d",&n,&s[0]); 77 for(int i=1;i<=n;i++){ 78 scanf("%d%d",&a[i],&s[i]); 79 for(int j=1;j<=a[i];j++){ 80 scanf("%d%d",&x,&y); 81 w[i].push_back(x); 82 c[i].push_back(y); 83 v[i][x].push_back(y); 84 } 85 for(int j=1;j<4;j++)sort(v[i][j].begin(),v[i][j].end()); 86 s[0]-=s[i]; 87 } 88 s[0]=max(s[0],0); 89 scanf("%d",&m); 90 for(int i=1;i<=m;i++){ 91 int p,x1,y1,x2,y2,cc; 92 scanf("%d%d%d%d%d",&p,&x1,&y1,&x2,&y2); 93 if (p==3)cc=oo; 94 else{ 95 scanf("%d",&cc); 96 if (p==1)cc=-cc; 97 } 98 if (!mat[x1][y1-1])mat[x1][y1-1]=++V; 99 if (!mat[x2][y2-1])mat[x2][y2-1]=++V; 100 sum[mat[x1][y1-1]][mat[x2][y2-1]]=cc; 101 } 102 memset(dp,oo,sizeof(dp)); 103 dp[0]=0; 104 for(int i=1;i<=n;i++) 105 if (!mat[i].size()){ 106 init(i); 107 for(int j=0;j<=42;j++)f[j]=query_123(i,j+s[i]); 108 merge(); 109 } 110 else{ 111 p[++p[0]]=i; 112 for(it=mat[i].begin();it!=mat[i].end();it++){ 113 x=(*it).first; 114 v[i][w[i][x]].erase(lower_bound(v[i][w[i][x]].begin(),v[i][w[i][x]].end(),c[i][x])); 115 } 116 init(i); 117 for(int j=-36;j<=42;j++)ff[p[0]][j+36]=query_123(i,j+s[i]); 118 } 119 memcpy(g,dp,sizeof(g)); 120 ans=oo; 121 dfs(1); 122 if (ans>=oo)ans=-1; 123 printf("%d",ans); 124 }