D. Maximum Sum of Products ###K //K
题目链接:https://codeforces.ml/problemset/problem/1519/D
思路: 可以预处理前后缀和 然后枚举翻转的终点 然后左右同时扫一遍得到答案
为了让长度为偶数的情况好处理 可以像manacher那样 把长度边为2*n 中间用0隔开
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e4+10; 4 const int mod=1e9+7; 5 #define ll long long 6 #define pi pair<int,int> 7 #define fi first 8 #define sc second 9 #define pb push_back 10 11 12 13 ll pre[maxn],suf[maxn]; 14 ll a[maxn],b[maxn]; 15 int n; 16 17 18 int main() 19 { 20 ios::sync_with_stdio(0); 21 cin.tie(0); 22 cin>>n; 23 for(int i=1;i<=n*2;i+=2) cin>>a[i]; 24 for(int i=1;i<=n*2;i+=2) cin>>b[i]; 25 for(int i=1;i<=n*2;i++) 26 { 27 pre[i]=pre[i-1]+a[i]*b[i]; 28 } 29 for(int i=n*2;i>=1;i--) 30 { 31 suf[i]=suf[i+1]+a[i]*b[i]; 32 } 33 ll ans=pre[n*2]; 34 for(int i=1;i<=n*2;i++) 35 { 36 ll sum=a[i]*b[i]; 37 for(int j=1;j<=n;j++) 38 { 39 int l=i-j,r=i+j; 40 if(l<=0||r>=n*2) break; 41 sum+=a[l]*b[r]+a[r]*b[l]; 42 ans=max(ans,sum+suf[r+1]+pre[l-1]); 43 } 44 45 } 46 47 cout<<ans<<'\n'; 48 49 50 51 }
也可以用像区间dp求最长回文串一样 f[i][j] 为翻转i j 能得到的额外贡献
每次更新状态 只需要让 a[i]*b[j]+a[j]*b[i] 与 a[i]*b[i]+b[j]*b[j] 作差即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=5e3+10; 4 const int mod=1e9+7; 5 #define ll long long 6 #define ull unsigned long long 7 #define pi pair<int,int> 8 #define fi first 9 #define sc second 10 #define pb push_back 11 12 13 ll a[maxn],b[maxn],f[maxn][maxn]; 14 15 int main() 16 { 17 ios::sync_with_stdio(false); 18 cin.tie(0); 19 int n;cin>>n; 20 for(int i=1;i<=n;i++) cin>>a[i]; 21 for(int i=1;i<=n;i++) cin>>b[i]; 22 ll sum=0,ans=0; 23 for(int i=1;i<=n;i++) sum+=a[i]*b[i]; 24 25 for(int len=2;len<=n;len++) 26 { 27 for(int i=1;i+len-1<=n;i++) 28 { 29 int j=i+len-1; 30 ll t=a[i]*b[i]+a[j]*b[j]; 31 ll tt=a[i]*b[j]+a[j]*b[i]; 32 f[i][j]=f[i+1][j-1]+tt-t; 33 ans=max(ans,f[i][j]); 34 } 35 } 36 cout<<sum+ans<<'\n'; 37 38 39 40 41 42 }