標籤:tar reverse 技術分享 view inpu while style test div
http://codeforces.com/contest/1060/problem/C
矩形中的和只和n,m數列在這上面的分別的和有關。比如1,2,3和7,8,9交叉形成的和=(1+2+3)*(7+8+9)=144。
而兩個的交叉是分別的選擇,無相互影響。
那麼,策略就是,我們先找到對於數列n來說的一個目標數列n_sum[],n_sum[i]記錄著n中所有連續長度為i的段中,和最小是多少。舉例來說:n=[3,4,2,2],那麼n_sum=[0,2,4,8,11],其中下標3的數是8,代表n中長為3的連續子序列中最小和是8。
怎麼得到的後面解釋,先把有這個n_sum和m_sum為前提。注意這兩個數列中的數值是遞增的。
有了n_sum和m_sum,n_sum的每個下標i,找到m_sum[j]*n_sum[i]<x就行了。因為兩個數列中的數值是遞增的,用雙指標記錄位置,可用o(n)做完。這樣等於窮舉所有長度搭配的可能。每次找到後,用ans=max(ans,i*j)就行了。
至於怎麼找每個長度的最小和,先複製n中內容到temp,先找長度1,等於min(n),然後每次temp[i]=n[i]+temp[i+1]就逐次累加長度了。這是o(n^2)複雜度的。
python太慢過不了,用c++重寫了一遍,花了一個半小debug的問題竟然又是出在爆int上,哎~
int是32bit 最大10^10
python版:
n, m = [int(x) for x in input().split()]ns = [int(x) for x in input().split()]ms = [int(x) for x in input().split()]k = int(input())def getlen(arr): ans = [0] start = arr[:] ans.append(min(arr)) for l in range(2, len(arr) + 1): minn = 10**16 for i in range(len(arr) - l + 1): start[i] = arr[i] + start[i + 1] minn = min(minn, start[i]) ans.append(minn) return ansnl=getlen(ns)ml=getlen(ms)j=0ans=0for i in reversed(range(n+1)): while j<m+1 and ml[j]*nl[i]<=k: j+=1 ans=max(ans,i*(j-1))print(ans)
View Code
c++版:
#include <iostream>#include <vector>#include <cstring>#include <algorithm>using namespace std;#define ll long longvector<ll> getlen(ll* a,ll l){ vector<ll> ans; ans.push_back(0); ll start[l]; memcpy(start, a, l*sizeof(ll)); ll minn=INT_MAX; for(ll i =0;i<l;i++) minn=min(minn,start[i]); ans.push_back(minn); for(ll k=2;k<=l;k++){ minn=INT_MAX; for(ll i=0;i<=l-k;i++){ start[i]=a[i]+start[i+1]; minn=min(minn,start[i]); } ans.push_back(minn); } return ans;}int main(int argc, char** argv){ ll n,m; cin>>n>>m; ll ns[n]; ll ms[m]; for(ll i=0;i<n;i++){ cin>>ns[i]; } for(ll i=0;i<m;i++){ cin>>ms[i]; } ll k; cin>>k; vector<ll> nl=getlen(ns,n); vector<ll> ml=getlen(ms,m); ll ans=0; ll j=1; for(ll i=n;i>0;i--){ while(j<m+1 && ml[j]*nl[i]<=k)j++; ans=max(ans,i*(j-1)); } cout<<ans; return 0;}
cf Maximum Subrectangle