[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;
}

猜你喜欢

转载自www.cnblogs.com/rrsb/p/9489587.html
今日推荐