Submission #504099

#TimeUsernameProblemLanguageResultExecution timeMemory
504099DeepessonZoltan (COCI16_zoltan)C++17
140 / 140
322 ms17124 KiB
#include <bits/stdc++.h> #define MAX 205000 const long long MOD = 1e9+7; typedef std::pair<long long,long long> pii; typedef std::pair<int,int*> pipo; ///The first number is the size of the sequence, and the second one the number of sequences pii comb(pii a,pii b){ if(a.first==b.first){ ///I'm multiplying MOD by two because I will divide by two later a.second%=(MOD*2); b.second%=(MOD*2); return {a.first,a.second+b.second%(MOD*2)}; }else return std::max(a,b); } ///Basic seg3 pii tab[MAX*4][2]={}; pii query(int l,int r,int x,int la=0,int ra=MAX-1,int pos=1){ if(la>r||ra<l)return tab[0][x]; if(la>=l&&ra<=r){ return tab[pos][x]; } int m = (la+ra)/2; return comb(query(l,r,x,la,m,pos*2),query(l,r,x,m+1,ra,(pos*2)+1)); } void update(int t,pii k,int x,int la=0,int ra=MAX-1,int pos=1){ if(la>t||ra<t)return; if(la==ra){ tab[pos][x]=comb(tab[pos][x],k); return; } int m = (la+ra)/2; update(t,k,x,la,m,pos*2); update(t,k,x,m+1,ra,(pos*2)+1); tab[pos][x]=comb(tab[pos*2][x],tab[(pos*2)+1][x]); } ///Binary exponentiation + Mod long long binpow(long long a,long long b,long long c){ long long r=1; while(b){ if(b&1)r=(r*a)%c; b/=2; a=(a*a)%c; } return r; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); ///You can always start an empty subsequence pii base = {0,1}; int N; std::cin>>N; int array[N]={}; for(auto&x:array)std::cin>>x; int curbesto=0; ///Coordinate Compression { std::vector<pipo> vec; for(auto&x:array)vec.push_back({x,&x}); std::sort(vec.begin(),vec.end()); int cur=3; int last=-1; for(auto&x:vec){ if(x.first!=last){ last=x.first; ++cur; } *(x.second)=cur; } curbesto=cur; } ///Longest decreasing subsequence (From end to start) ///Notice that if you reverse this sequence it's increasing for(int i=N-1;i!=-1;--i){ int x = array[i]; auto resposta=query(x+1,MAX-1,0); resposta=comb(resposta,base); update(x,{resposta.first+1,resposta.second},0); } ///Longest increasing subsequence (From end to start) ///Notice that if you reverse this sequence it's decreasing for(int i=N-1;i!=-1;--i){ int x = array[i]; auto resposta=query(0,x-1,1); resposta=comb(resposta,base); update(x,{resposta.first+1,resposta.second},1); } ///The idea is the following: ///You want the largest decreasing subsequence smaller than X (you will throw everything to the left) ///And the largest increasing subsequence greater or equal than X(You will throw to the right) ///The other N-(LIS.size) don't really matter, you can throw wherever you want. ///That's why we will use binary exponentiation ///Note: ///When I say increasing (or decreasing) I'm referring from the start (position 0) to the end (position N-1) pii best={1,N}; for(int i=4;i<curbesto+1;++i){ auto a = query(i,MAX-1,0); a=comb(a,base); auto b = query(i-1,i-1,1); b=comb(b,base); pii c = {a.first+b.first,a.second*b.second}; best=comb(best,c); } ///The first element can't be thrown to the right nor left: It needs to be in the middle ///That's why we are dividing by two :) int menos=1; if(!(best.second&1)){ menos=0; best.second/=2; } std::cout<<best.first<<" "<<((((best.second))*binpow(2,N-best.first-menos,MOD))%MOD)<<"\n"; }
#Verdict Execution timeMemoryGrader output
Fetching results...