[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]魔法商店的主要内容,如果未能解决你的问题,请参考以下文章

LOJ #3166. 「CEOI2019」魔法树

LOJ#2369. 「BalticOI 2008」魔法石

loj2985WC2019I君的商店

片段“F1”不能在这里传播,因为“节点”类型的对象永远不能是“商店”类型

BZOJ4861[Beijing2017]魔法咒语 矩阵乘法+AC自动机+DP

AC自动机 + 矩阵优化 --- [BJOI2017]魔法咒语