zoukankan      html  css  js  c++  java
  • Codeforces 575A. Fibonotci 题解

    题目大意:

    • 定义(f_i=s_{i-1}f_{i-1}+s_{i-2}f_{i-2},f_0=0,f_1=0)
    • 在通常情况下(s_i=s_{i mod n})
    • (m)个位置(s_i)特殊给定。
    • (f_kmod p)

    题目链接:575A. Fibonotci


    题解:由于(kleq 10^{18}),很容易考虑到矩阵快速幂,如果没有特殊位置,可以直接矩阵快速幂做完,特殊位置特殊考虑,如果暴力求特殊位置所在循环节的矩阵值的话,时间复杂度是(O(nm))的,所以考虑用线段树维护转移矩阵,每一次特殊位置就直接单点修改随后改回来,然后就做完了。

    但是在实现时会有一个很麻烦的地方,就是一次修改可能会影响到两个循环节,所以需要将特殊位置拆开成两个,在这种情况下,如果是在原序列上修改的话会有很多细节处理起来很麻烦,所以可以在一开始把所有的转移矩阵存下来,每一次对转移矩阵进行修改。

    时间复杂度:(O(nlog k))

    代码:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int Maxn=50000;
    typedef long long ll;
    int n,m;
    ll K;
    int Mod;
    int s[Maxn+5];
    struct Operation{
    	ll pos;
    	int val,x;
    	friend bool operator <(Operation p,Operation q){
    		return p.pos<q.pos;
    	}
    }op[Maxn<<1|5];
    struct Matrix{
    	int a[2][2];
    	Matrix(){
    		a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;
    	}
    	friend Matrix operator *(Matrix a,Matrix b){
    		Matrix ans;
    		for(int i=0;i<2;i++){
    			for(int j=0;j<2;j++){
    				for(int k=0;k<2;k++){
    					ans.a[i][j]=(ans.a[i][j]+1ll*b.a[i][k]*a.a[k][j])%Mod;
    				}
    			}
    		}
    		return ans;
    	}
    };
    Matrix a[Maxn+5],tmp[Maxn+5],d[Maxn+5];
    ll b[Maxn+5];
    int len;
    Matrix val[Maxn<<2|5];
    void insert(int x,Matrix a,int root=1,int left=1,int right=n){
    	if(left==right){
    		val[root]=a;
    		return;
    	}
    	int mid=(left+right)>>1;
    	if(x<=mid){
    		insert(x,a,root<<1,left,mid);
    	}
    	else{
    		insert(x,a,root<<1|1,mid+1,right);
    	}
    	val[root]=(val[root<<1]*val[root<<1|1]);
    }
    Matrix quick_power(Matrix a,ll b){
    	Matrix ans;
    	ans.a[0][0]=ans.a[1][1]=1;
    	while(b){
    		if(b&1){
    			ans=(ans*a);
    		}
    		b>>=1;
    		a=(a*a);
    	}
    	return ans;
    }
    int main(){
    	scanf("%lld%d",&K,&Mod);
    	if(K==0){
    		puts("0");
    		return 0;
    	}
    	if(Mod==1){
    		puts("0");
    		return 0;
    	}
    	if(K==1){
    		puts("1");
    		return 0;
    	}
    	scanf("%d",&n);
    	ll bel_k=K/n;
    	for(int i=0;i<n;i++){
    		scanf("%d",&s[i]);
    		s[i]%=Mod;
    	}
    	s[n]=s[0];
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		scanf("%lld%d",&op[i].pos,&op[i].val);
    		op[i].pos;
    		op[i].val%=Mod;
    		op[i+m]=op[i];
    		op[i+m].pos++;
    		op[i].x=1;
    	}
    	m<<=1;
    	sort(op+1,op+1+m);
    	for(int i=1;i<=n;i++){
    		a[i].a[0][0]=0;
    		a[i].a[0][1]=1;
    		a[i].a[1][0]=s[i-1];
    		a[i].a[1][1]=s[i];
    		insert(i,a[i]);
    		tmp[i]=a[i];
    	}
    	while(op[m].pos>K){
    		m--;
    	}
    	Matrix all=val[1];
    	for(int i=1,j;i<=m;i=j+1){
    		j=i;
    		ll bel=(op[i].pos-1)/n;
    		while(j<m&&bel==(op[j+1].pos-1)/n){
    			j++;
    		}
    		for(int k=i;k<=j;k++){
    			int pos=(op[k].pos-1)%n+1;
    			tmp[pos].a[1][op[k].x]=op[k].val;
    			insert(pos,tmp[pos]);
    		}
    		if(bel==bel_k){
    			break;
    		}
    		d[++len]=val[1];
    		b[len]=bel;
    		for(int k=i;k<=j;k++){
    			int pos=(op[k].pos-1)%n+1;
    			tmp[pos]=a[pos];
    			insert(pos,a[pos]);
    		}
    	}
    	Matrix ans;
    	ans.a[0][0]=ans.a[1][1]=1;
    	ll last=0;
    	for(int i=1;i<=len;i++){
    		ans=ans*quick_power(all,b[i]-last);
    		ans=ans*d[i];
    		last=b[i]+1;
    	}
    	ans=ans*quick_power(all,bel_k-last);
    	for(int i=1;i<=K%n;i++){
    		ans=ans*tmp[i];
    	}
    	printf("%d
    ",ans.a[0][1]);
    	return 0;
    }
    
  • 相关阅读:
    范仁义网站刷题教程
    心得体悟帖---200115(对人要好)(浪费时间可耻)
    心得体悟帖---200114(解决问题啊)(解决问题)
    legend3---laravel缓存操作基本使用实例
    JS动态修改页面EasyUI datebox不生效、EasyUI动态添加Class、EasyUI动态渲染解析解决方案
    Java正则表达式入门
    Android中scrollview的scrollto方法不起作用的办法
    Android中监听ScrollView滑动停止和滑动到底部
    视频
    Android Scroller类的详细分析
  • 原文地址:https://www.cnblogs.com/withhope/p/13364780.html
Copyright © 2011-2022 走看看