[8月4日衢州二中] problem C
题目描述
给出两个序列{a[i]}、{b[i]},一个排列 p 的权值定义为∑a[i]*b[p[i]]。
一开始有一个排列 P 作为限制,表示任意与 P 有某一位相同的排列均不合法。 初始时 P[i]=i,有 q 次操作,每次交换 P 中的两个元素。 在每次操作后,求出此时所有合法排列的权值中的最大值。
输入
第一行 n,q
第二行依次给出 a 中元素
第三行依次给出 b 中元素
接下来 q 行每行两个数 a、b,表示交换 P[a]、P[b]
输出
q 行,每行的输出见题述
提示
对于所有数据n<=30000,m<=30000,a和b在10^6范围内。
分块+插头DP
#pragma GCC optimize("-Ofast") #include<bits/stdc++.h> using namespace std; #define pii pair<int,int> #define N 30007 #define fi first #define se second #define LL long long pii a[N],b[N]; int ida[N],idb[N],can[N],x,y,n,q,usd[N],cat,to[16],oz[16],tot,st,ed,L[N],R[N],l,r,belong[N]; LL dp[N][36],Dp[N][36]; int Blo,state,will; #define max(a,b) (a>b?a:b) long long ans; int bitcount(int x) { if (!x) return 0; return bitcount(x-(x&-x))+1; } void Pre(){ for (int i=0;i<16;i++) if (bitcount(i)==2) to[i]=tot,oz[tot++]=i; } inline void clear(int l,int r){ for (int i=l;i<=r;i++) for (int j=0;j<36;j++) dp[i][j]=0; } void dfs(int x,int leaf,int state,LL oj){ if (!leaf) { st=state>>4; ed=state&15; if (bitcount(st)!=2||bitcount(ed)!=2) return; st=to[st]; ed=to[ed]; dp[x-1][st*6+ed]=max(dp[x-1][st*6+ed],oj); return; } state<<=1; for (int i=0;i<5;i++) { if ((state>>i)&1) continue; if (idb[can[a[x].se]]==x+2-i) continue; dfs(x+1,leaf-1,state|(1<<i),oj+1ll*a[x].fi*b[x+2-i].fi); } } //void Dfs(int st,int x,int leaf,int state,LL oj){ // if (!leaf) { //// if ((state&3)) return; //// cerr<<state<<endl; // ed=(state)&15; // if (bitcount(ed)!=2) return; // dp[x-1][st*6+to[ed]]=max(dp[x-1][st*6+to[ed]],oj); // return; // } // state<<=1; // for (int i=0;i<5;i++) { // if ((state>>i)&1) continue; // if (idb[can[a[x].se]]==x+2-i) continue; //// assert(bitcount(state)+1==bitcount(state|(1<<i))); // Dfs(st,x+1,leaf-1,state|(1<<i),oj+1ll*a[x].fi*b[x+2-i].fi); // } //} void pre(int x){ l=L[x]; r=R[x]; clear(l,r); dfs(l,4,0,0); for (int i=l+4;i<=r;i++) { for (int k=0;k<36;k++) { st=oz[k/6],ed=oz[k%6]; if ((ed>>3)!=1) { if (idb[can[a[i].se]]==i-2) continue; state=ed<<1; will=k/6*6+to[state]; dp[i][will]=max(dp[i][will],dp[i-1][k]+1ll*a[i].fi*b[i-2].fi); } else { state=(ed-8)<<1; for (int j=0;j<4;j++) { if ((state>>j)&1) continue; if (idb[can[a[i].se]]==i+2-j) continue; state^=1<<j; will=k/6*6+to[state]; dp[i][will]=max(dp[i][will],dp[i-1][k]+1ll*a[i].fi*b[i+2-j].fi); state^=1<<j; } } } } } LL sta[701][6],anw; void Merge(){ if (belong[n]==1) {printf("%lld\n",dp[n][5]); return;} memset(sta,0,sizeof sta); anw=0; for (int i=0;i<6;i++) sta[1][i]=dp[R[1]][i]; for (int i=2;i<belong[n];i++) for (int j=0;j<36;j++) sta[i][j%6]=max(sta[i-1][to[15-oz[j/6]]]+dp[R[i]][j],sta[i][j%6]); for (int i=5;i<36;i+=6) anw=max(anw,sta[belong[n]-1][to[15-oz[i/6]]]+dp[n][i]); printf("%lld\n",anw); } signed main() { Pre(); scanf("%d%d",&n,&q); for (int i=1;i<=n;i++) scanf("%d",&a[i].fi),a[i].se=i; for (int i=1;i<=n;i++) scanf("%d",&b[i].fi),b[i].se=i; sort(a+1,a+n+1); sort(b+1,b+n+1); for (int i=1;i<=n;i++) ida[a[i].se]=i,idb[b[i].se]=i; for (int i=1;i<=n;i++) can[i]=i; Blo=max(sqrt(n/6),5.0); for (int i=1;i<=n;i++) belong[i]=i/Blo+1; if (n%Blo<4) for (int i=n/Blo*Blo;i<=n;i++) belong[i]--; for (int i=1;i<=n;i++) { if (R[belong[i]]<i) R[belong[i]]=i; if (!L[belong[i]]) L[belong[i]]=i; } // for (int i=1;i<=n;i++) belong[i]=1; // L[1]=1; R[1]=n; // for(int i = 1; i <= belong[n]; ++i) cerr << L[i] << ' '<<R[i]<<endl; for (int i=1;i<=belong[n];i++) pre(i); // Merge(); while (q--) { scanf("%d%d",&x,&y); swap(can[x],can[y]); // memset(usd,0,sizeof usd); if (belong[ida[x]]==belong[ida[y]]) pre(belong[ida[x]]); else pre(belong[ida[x]]),pre(belong[ida[y]]); Merge(); } return 0; }