[loj3301]魔法商店
Posted PYWBKTDA
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[loj3301]魔法商店相关的知识,希望对你有一定的参考价值。
令$A=\\{a_{1},a_{2},...,a_{s}\\}$,若$k\\not\\in A$,那么恰存在一个$A\'\\subseteq A$使得$c_{k}=\\bigoplus_{x\\in A\'}c_{x}$
存在性:若不存在,将$k$加入$A$中仍然为合法的集合,与$|A|$最大矛盾
唯一性:若存在多个,将其中两个集合异或(即保留在这两个集合中出现奇数次的元素),显然这个异或的结果非空且所有元素异或和为0,与$A$为合法的集合矛盾
(为了方便,称$A\'$为$k$的表示集合)
此时,限制即$\\forall k\\not\\in A$且$x\\in A\',v_{x}\\le v_{k}$(其中$A\'$为$k$的表示集合)
必要性:若不满足此性质,显然用$k$替换$x$价格和更小
充分性:考虑合法方案$B$,满足$|B|=|A|$,来证明$\\sum_{x\\in A}v_{x}\\le \\sum_{x\\in B}v_{x}$
考虑$k\\in A$且$k\\not\\in B$,同理恰存在一个$B\'\\subseteq B$使得$c_{k}=\\bigoplus_{x\\in B\'}c_{x}$
若$\\forall x\\in B\'$且$x\\not\\in A$,其的表示集合若包含$k$,那么即有$v_{k}\\le v_{x}$,用$k$替换$x$不劣
若所有$x$的表示集合都不包含$k$,那么将这些表示集合和$(A\\cap B\')\\cup\\{k\\}$异或,显然这个异或的结果非空($k$必然只出现一次)且所有元素异或和为0,矛盾
因此,重复此过程,每一次$|A\\cap B|$恰好增加1,那么必然会有$|A\\cap B|=|A|=|B|$,也即$A=B$
关于如何求$A\'$可以使用线性基,复杂度为$o(nm)$(实现中比较懒用了$o(\\frac{n^{2}m}{\\omega})$)
(关于价格和最大的方案类似,也可以得到若干个不等式)
得到不等式后,即是一个保序回归的问题,做法参考[tc14634]ExtremeSpanningTrees
(另外,其中的引理中$S$应改为$[0,10^{6}]$,因为是平方,所以加1的答案增加$\\Delta$但减1不一定使答案增加$-\\Delta$)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 #define M 105 5 #define ll unsigned long long 6 #define oo 0x3f3f3f3f 7 #define vi vector<int> 8 struct ji{ 9 int nex,to; 10 ll len; 11 }edge[N*M*4]; 12 queue<int>q; 13 bitset<N>BT,bt[M]; 14 int E,n,m,x,w[N],vis[N],head[N],work[N],a[N],d[N],bl[N],ans[N],lim[N][N]; 15 ll sum,c[N],val[M]; 16 void add(ll k,int x){ 17 ll o=1; 18 BT.reset(); 19 BT[x]=1; 20 for(int i=63;i>=0;i--) 21 if (k&(o<<i)){ 22 if (!val[i]){ 23 val[i]=k; 24 bt[i]=BT; 25 } 26 k^=val[i]; 27 BT^=bt[i]; 28 } 29 } 30 void query(ll k,int x,int p){ 31 ll o=1; 32 BT.reset(); 33 for(int i=63;i>=0;i--) 34 if (k&(o<<i)){ 35 BT^=bt[i]; 36 k^=val[i]; 37 } 38 for(int i=1;i<=n;i++) 39 if (BT[i]){ 40 if (!p)lim[i][x]=1; 41 else lim[x][i]=1; 42 } 43 } 44 ll sqr(ll k){ 45 return k*k; 46 } 47 bool cmp(int x,int y){ 48 return bl[x]<bl[y]; 49 } 50 void init(){ 51 E=0; 52 memset(head,-1,sizeof(head)); 53 } 54 void add(int x,int y,ll z){ 55 edge[E].nex=head[x]; 56 edge[E].to=y; 57 edge[E].len=z; 58 head[x]=E++; 59 if (E&1)add(y,x,0); 60 } 61 bool bfs(){ 62 memset(d,oo,sizeof(d)); 63 d[0]=0; 64 q.push(0); 65 while (!q.empty()){ 66 int k=q.front(); 67 q.pop(); 68 for(int i=head[k];i!=-1;i=edge[i].nex) 69 if ((edge[i].len)&&(d[edge[i].to]==oo)){ 70 d[edge[i].to]=d[k]+1; 71 q.push(edge[i].to); 72 } 73 } 74 return d[n+1]<oo; 75 } 76 ll dfs(int k,ll s){ 77 if (k>n)return s; 78 for(int &i=work[k];i!=-1;i=edge[i].nex) 79 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){ 80 ll p=dfs(edge[i].to,min(s,edge[i].len)); 81 if (p){ 82 edge[i].len-=p; 83 edge[i^1].len+=p; 84 return p; 85 } 86 } 87 return 0; 88 } 89 void dinic(){ 90 while (bfs()){ 91 memcpy(work,head,sizeof(work)); 92 while (dfs(0,1e12)); 93 } 94 } 95 void dfs(int k){ 96 if (vis[k])return; 97 vis[k]=1; 98 for(int i=head[k];i!=-1;i=edge[i].nex) 99 if (edge[i].len)dfs(edge[i].to); 100 } 101 void dfs(int l,int r,int x,int y){ 102 if (x==y){ 103 for(int i=l;i<=r;i++)ans[a[i]]=x; 104 return; 105 } 106 int mid=(x+y>>1); 107 init(); 108 for(int i=l;i<=r;i++){ 109 ll wx=sqr(w[a[i]]-mid),wy=sqr(w[a[i]]-mid-1); 110 if (wx>wy){ 111 bl[a[i]]=1; 112 add(0,i,wx-wy); 113 } 114 else{ 115 bl[a[i]]=0; 116 add(i,n+1,wy-wx); 117 } 118 } 119 for(int i=l;i<=r;i++) 120 for(int j=l;j<=r;j++) 121 if (lim[a[i]][a[j]])add(i,j,oo); 122 dinic(); 123 memset(vis,0,sizeof(vis)); 124 dfs(0); 125 for(int i=head[0];i!=-1;i=edge[i].nex) 126 if (!vis[edge[i].to])bl[a[edge[i].to]]=0; 127 for(int i=head[n+1];i!=-1;i=edge[i].nex) 128 if (vis[edge[i].to])bl[a[edge[i].to]]=1; 129 sort(a+l,a+r+1,cmp); 130 for(int i=l;i<=r+1;i++){ 131 if ((bl[a[i]])||(i>r)){ 132 if (l<i)dfs(l,i-1,x,mid); 133 if (i<=r)dfs(i,r,mid+1,y); 134 return; 135 } 136 } 137 } 138 int main(){ 139 scanf("%d%d",&n,&m); 140 for(int i=1;i<=n;i++)scanf("%llu",&c[i]); 141 for(int i=1;i<=n;i++)scanf("%d",&w[i]); 142 for(int i=1;i<=m;i++){ 143 scanf("%d",&x); 144 add(c[x],x); 145 vis[x]=1; 146 } 147 for(int i=1;i<=n;i++) 148 if (!vis[i])query(c[i],i,0); 149 memset(vis,0,sizeof(vis)); 150 memset(val,0,sizeof(val)); 151 for(int i=1;i<=m;i++){ 152 scanf("%d",&x); 153 add(c[x],x); 154 vis[x]=1; 155 } 156 for(int i=1;i<=n;i++) 157 if (!vis[i])query(c[i],i,1); 158 for(int i=1;i<=n;i++)a[i]=i; 159 dfs(1,n,0,1e6); 160 for(int i=1;i<=n;i++)sum+=sqr(ans[i]-w[i]); 161 printf("%lld",sum); 162 }
以上是关于[loj3301]魔法商店的主要内容,如果未能解决你的问题,请参考以下文章
片段“F1”不能在这里传播,因为“节点”类型的对象永远不能是“商店”类型