layout: post
title: 南昌邀請賽網絡賽
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces
- DPc++
傳送門網絡
今天個人問題:
1:沒有看D,一眼認爲D是大模擬題,就不作了,(其實D只是個DP並且我是能夠切掉的)
2:不去作I題,其實I題我有基本思路可是個人想法代碼量太大。(太懶)
3:夢遊過久,沒有及時去開新題。坐等翻譯
4:C題沒想清楚就上了,後面發現本身沒有大數快速冪板子,浪費時間post
D這題是真特麼能夠作得出來,學弟讓我作 我第一眼看到圖,覺得是個大模擬,我操 結果賽後一發AC fuckui
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e5+50; #define bug cout<<"hello"<<endl; int num[maxn]; /// 0 1 2 3 4 5 6 7 8 9 int a[50]={6,2,5,5,4,5,6,3,7,6}; ll mx[20][150],mi[150][20];///幾位用了幾根; ll dp[200][1000];///前幾個數字用了多少根 void init(){ for(int i=1;i<20;i++) for(int j=0;j<150;j++){ mx[i][j]=-1e18,mi[i][j]=1e18; } mx[0][0]=mi[0][0]=0; for(int i=0;i<20;i++){ for(int j=0;j<150;j++){ for(int k=0;k<=9;k++){ int ned=a[k]; if(i==0&&k==0)continue; if(mx[i][j]!=-1e18){ mx[i+1][j+ned]=max(mx[i+1][j+ned],mx[i][j]*10+k); } if(mi[i][j]!=1e18){ mi[i+1][j+ned]=min(mi[i+1][j+ned],mi[i][j]*10+k); } } } } // cout<<mx[1][2]<<endl; // cout<<mx[1][7]<<endl; } int main() { init(); int t; cin>>t; while(t--){ int n; cin>>n; string s; cin>>s; int cnt=0; int k=1; memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ if(s[i]=='-'){ cnt++; ++k; } else if(s[i]=='+'){ cnt+=2; ++k; } else{ cnt+=a[s[i]-'0']; num[k]++; } } for(int i=0;i<=n+10;i++){ for(int j=0;j<1000;j++){ dp[i][j]=-1e18; } } // cout<<"cnt="<<cnt<<endl; dp[0][0]=0; for(int i=1;i<=k;i++){ if(i==1){ for(int j=1;j<=cnt;j++){ for(int len=1;len<100&&len<=j;len++){ if(dp[i-1][j-len]!=-1e18&&mx[num[i]][len]!=-1e18){ dp[i][j]=max(dp[i][j],dp[i-1][j-len]+mx[num[i]][len]); // cout<<"a[i]="<<num[i]<<" len="<<len<<endl; // cout<<"mx[a[i][len]="<<mx[num[i]][len]<<endl; // cout<<"a[i]="<<num[i]<<endl; } } } } else{ for(int j=1;j<=cnt;j++){ for(int len=1;len<100;len++){ if(len+2<=j&&dp[i-1][j-len-2]!=-1e18&&mx[num[i]][len]!=-1e18){ dp[i][j]=max(dp[i][j],dp[i-1][j-len-2]+mx[num[i]][len]); } if(len+1<=j&&dp[i-1][j-len-1]!=-1e18&&mi[num[i]][len]!=1e18){ dp[i][j]=max(dp[i][j],dp[i-1][j-len-1]-mi[num[i]][len]); } } } } } cout<<dp[k][cnt]<<endl; } return 0; }
單調棧處理出 左邊界和右邊界,而後貪心選取前綴和差分一下。spa
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e5+50; #define bug cout<<"hello"<<endl; int ls[maxn],rs[maxn]; ll sum[maxn]; int a[maxn]; stack<int>st; ll mx[maxn<<2],mi[maxn<<2]; void build(int o,int l,int r){ if(l==r){ mx[o]=sum[l]; mi[o]=sum[r]; return; } int mid=(l+r)/2; build(o<<1,l,mid); build(o<<1|1,mid+1,r); mx[o]=max(mx[o<<1],mx[o<<1|1]); mi[o]=min(mi[o<<1],mi[o<<1|1]); } ll querymi(int o,int l,int r,int ql,int qr){ // cout<<"o="<<o<<endl; if(ql<=l&&qr>=r){ return mi[o]; } int mid=(l+r)/2; ll ans=1e18; if(ql<=mid)ans=min(ans,querymi(o<<1,l,mid,ql,qr)); if(qr>mid)ans=min(ans,querymi(o<<1|1,mid+1,r,ql,qr)); return ans; } ll querymx(int o,int l,int r,int ql,int qr){ if(ql<=l&&qr>=r){ return mx[o]; } int mid=(l+r)/2; ll ans=-1e18; if(ql<=mid)ans=max(ans,querymx(o<<1,l,mid,ql,qr)); if(qr>mid)ans=max(ans,querymx(o<<1|1,mid+1,r,ql,qr)); return ans; } int main() { int n; cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; sum[i]=sum[i-1]+a[i]; } build(1,0,n); a[0]=a[n+1]=-1e9; st.push(0); for(int i=1;i<=n;i++){ while(!st.empty()&&a[st.top()]>=a[i])st.pop(); ls[i]=st.top(); st.push(i); } while(!st.empty())st.pop(); st.push(n+1); for(int i=n;i;i--){ while(!st.empty()&&a[st.top()]>=a[i])st.pop(); rs[i]=st.top(); st.push(i); } ll ans=0; for(int i=1;i<=n;i++){ int l1=ls[i],r1=i-1; int l2=i,r2=rs[i]-1; if(a[i]<0){ ans=max(ans,a[i]*(querymi(1,0,n,l2,r2)-querymx(1,0,n,l1,r1))); } else{ ans=max(ans,a[i]*(querymx(1,0,n,l2,r2)-querymi(1,0,n,l1,r1))); } } cout<<ans<<endl; return 0; }