Submission #114823

#TimeUsernameProblemLanguageResultExecution timeMemory
114823user202729Fibonacci representations (CEOI18_fib)C++17
65 / 100
1395 ms262144 KiB
// #ifndef _GLIBCXX_DEBUG
// #define NDEBUG
// #endif

#include<iostream>
#include<array>
#include<vector>
#include<algorithm>
#include<cassert>
#include<set>

#ifdef _GLIBCXX_DEBUG
#include<sstream>
#define cin cin_
namespace std{
	std::stringstream cin(R"(
4
4 1 1 5
	)");
};
#endif

int constexpr MOD=1000000007;

template<int M,int N>
struct Matrix{
	std::array<std::array<int,N>,M> a;
	std::array<int,N>& operator[](int r){return a[r];}
	Matrix operator+(Matrix b)const{
		Matrix ans;
		for(int r=0;r<M;++r)for(int c=0;c<N;++c){
			int x=a[r][c]+b[r][c];
			if(x>=MOD)x-=MOD;
			ans[r][c]=x;
		}
		return ans;
	}
	Matrix operator-(Matrix b)const{
		Matrix ans;
		for(int r=0;r<M;++r)for(int c=0;c<N;++c){
			int x=a[r][c]-b[r][c];
			if(x<0)x+=MOD;
			ans[r][c]=x;
		}
		return ans;
	}
	template<int P>
	Matrix operator*(Matrix<N,P> b)const{
		Matrix<M,P> ans{};
		for(int i=0;i<M;++i)
		for(int j=0;j<N;++j)
		for(int k=0;k<P;++k){
			int& x=ans[i][k];
			x=(a[i][j]*(int64_t)b[j][k]+x)%MOD;
		}
		return ans;
	}
};

Matrix<2,2> trmat(int diff){
	/*
	Given a Matrix<1,2> with {{f0,f1}}, multiply it by trmat(diff)
	to get the matrix of next i value.
	*/
	assert(diff<MOD&&diff>=2);
	return Matrix<2,2>{{{
		{diff/2ull,    1},
		{(diff-1)/2ull,1}
	}}};
}

struct ST{
	struct Node{
		// represent a range of nodes
		Matrix<2,2> tr;
		int min,max;

		Node():min(-1){
			// (empty set)
		}

		Node(int val):tr{{{
			{1,0},{0,1}
		}}},min(val),max(val){
			assert(0<=val);
		}

		bool empty()const{
			return min<0;
		}

		Node(Node l,Node r){
			if(l.empty())
				*this=r;
			else if(r.empty())
				*this=l;
			else{
				tr=l.tr*trmat(r.min-l.max)*r.tr;
				min=l.min;
				max=r.max;
			}
		}
	};
	std::vector<Node> d;
	std::vector<int> vals;
	int ofs; // offset - how valindex coer to index on (d) (see index func below)

	int index(int valindex)const{
		valindex+=ofs;
		if(valindex>=d.size())valindex-=d.size()/2;
		return valindex;
	}

	ST(std::vector<int> _vals):
		d(_vals.size()*2), // initially all nodes are empty
		vals(std::move(_vals))
	{
		int const n=vals.size();

		ofs=1;
		while(ofs<n)ofs*=2;

		assert(n>0);
		// for(int i=0;i<n;++i)
		// 	d[index(i)]=Node(vals[i]);
		// for(int i=n-1;i;--i)
		// 	d[i]=Node(d[i<<1],d[i<<1|1]);
	}

	int get()const{
		Node root=d[1];
		assert(!root.empty());
		int s0=root.min;
		Matrix<1,2> f0{{{
			{s0/2u,1}
		}}}; // f[i=0]
		auto fn=f0*root.tr;
		return (fn[0][0]+fn[0][1])%MOD;
	}

	void set(int val,bool on){
		auto it=std::lower_bound(begin(vals),end(vals),val);
		assert(*it==val);
		int ind=index(it-begin(vals));
		bool currently_on=!d[ind].empty();
		assert(on!=currently_on);

		if(on)
			d[ind]=Node(val);
		else
			d[ind]=Node();

		for(ind>>=1;ind;ind>>=1)
		 	d[ind]=Node(d[ind<<1],d[ind<<1|1]);
	}
};

int main(){
	std::ios::sync_with_stdio(0);std::cin.tie(0);
	int n;std::cin>>n;
	std::vector<int> a(n);
	for(int& x:a){
		std::cin>>x;
		--x;
	}

	std::set<int> s; // zeckendorf repr

	struct Event{
		enum Type{
			ADD,REMOVE,QUERY
		};
		Type t;
		int n;
	};
	std::vector<Event> evs;

	std::vector<int> stk;
	for(int x:a){
		// add F[x] to s
		assert(stk.empty());
		stk.push_back(x);
#define x DONT_USE_THIS

		do{ // TODO: reduce (nnum*log) to (nnum+log)
			int y=stk.back();stk.pop_back();
			auto it=s.lower_bound(y-1);
			if(it==s.end()||*it>y+1){
				s.insert(y);
				evs.push_back({Event::ADD,y});
			}else if(*it<y){
				assert(*it==y-1);
				evs.push_back({Event::REMOVE,*it});
				s.erase(it);
				stk.push_back(y+1);
			}else if(*it==y){
				evs.push_back({Event::REMOVE,*it});
				s.erase(it);
				stk.push_back(y+1);
				if(y==0){ // assume F[-1] == 1 and F[-2] == 0
					assert(y-2 == -2);
					continue;
				}else
					stk.push_back(std::max(0,y-2));
			}else{
				assert(*it==y+1);
				evs.push_back({Event::REMOVE,*it});
				s.erase(it);
				stk.push_back(y+2);
			}
		}while(!stk.empty());

		evs.push_back({Event::QUERY,0});
		/* // how to compute a query the naive way
		int const n=s.size();
		std::vector<int> f0(n),f1(n);
		assert(n>0);
		int s0=*s.begin();
		f0[0]=s0/2u; // [i] = number of repr of [0..i] -> F{x | x<s[i]}
		f1[0]=1; // ~~~ but with F(s[i])

		auto it=s.begin();++it;
		for(int i=1,
				last=s0; // s[i-1]
				it!=s.end();++i,last=*it++){
			int diff=*it-last; // s[i]-s[i-1]
			f1[i]=(
					f0[i-1]+f1[i-1]
				)%MOD;
			f0[i]=(
					f0[i-1]*(diff/2ull)+f1[i-1]*((diff-1)/2ull)
				)%MOD;
		}

		std::cout<<(f0.back()+f1.back())%MOD<<'\n';
		*/
	}

	s.clear();
#define s DONT_USE_THIS

	std::vector<int> vals;
	for(Event e:evs)
		if(e.t==Event::ADD)
			vals.push_back(e.n);
	std::sort(begin(vals),end(vals));
	vals.erase(std::unique(begin(vals),end(vals)),end(vals));

	ST t(std::move(vals));
#define vals DONT_USE_THIS
	for(Event e:evs){
		switch(e.t){
			case Event::ADD:
				t.set(e.n,true);
				break;
			case Event::REMOVE:
				t.set(e.n,false);
				break;
			case Event::QUERY:
				std::cout<<t.get()<<'\n';
				break;
		}
	}
}
	

Compilation message (stderr)

fib.cpp: In function 'Matrix<2, 2> trmat(int)':
fib.cpp:67:8: warning: narrowing conversion of '(((long long unsigned int)diff) / 2)' from 'long long unsigned int' to 'int' inside { } [-Wnarrowing]
   {diff/2ull,    1},
    ~~~~^~~~~
fib.cpp:68:12: warning: narrowing conversion of '(((long long unsigned int)(diff - 1)) / 2)' from 'long long unsigned int' to 'int' inside { } [-Wnarrowing]
   {(diff-1)/2ull,1}
    ~~~~~~~~^~~~~
fib.cpp: In member function 'int ST::index(int) const':
fib.cpp:110:14: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   if(valindex>=d.size())valindex-=d.size()/2;
      ~~~~~~~~^~~~~~~~~~
fib.cpp: In member function 'int ST::get() const':
fib.cpp:135:7: warning: narrowing conversion of '(((unsigned int)s0) / 2)' from 'unsigned int' to 'int' inside { } [-Wnarrowing]
    {s0/2u,1}
     ~~^~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...