zoukankan      html  css  js  c++  java
  • bzoj4490 随机数生成器Ⅱ加强版

    题目链接

    题意

    给出参数(C_1,C_2,P)按如下方式生成一个长度为(n imes m)的序列(x):

    (x_0 = C_1,x_1=C2)

    (x_i=(x_{i-1}+x_{i-1}) \% P ; (i > 1))

    然后按如下方式生成一个长度为(n imes m)的序列(a)

    [a_i=sumlimits_{j=0}^ix_j^2\%P ]

    然后现在进行(Q)次操作,每次操作给出两个参数(k1,k2)。表示交换(k1,k2)的值。

    然后把序列(a)按顺序放到一个(n imes m)的网格中。

    要求出一种方案,使得从((1,1))走到((n,m)),所经过的数字排列起来字典序最小。

    思路

    容易发现,其实就是快速求出(a_i)

    然后就推一下式子。

    [x_i^2=x_{i-1}^2+2x_{i-1}x_{i-2}+x_{i-2}^2 ]

    [x_{i-1}^2=x_i^2-x_{i-2}^2-2x_{i-1}x_{i-2} ]

    [x_{i-1}^2=(x_i+x_{i-2}) imes(x_i-x_{i-2}) - 2x_{i-1}x_{i-2} ]

    [x_{i-1}^2=x_{i-1}(x_i+x_{i-2}) - 2x_{i-1}x_{i-2} ]

    [x_{i-1}^2=x_ix_{i-1}+x_{i-1}x_{i-2}-2x_{i-1}x_{i-2} ]

    [x_{i-1}^2=x_ix_{i-1}-x_{i-1}x_{i-2} ]

    也就是说

    [x_i^2=x_{i+1}x_i-x_ix_{i-1} ]

    这样也就是容易得到

    [a_i=x_{i+1}x_i-C_1(C_2-C_1) ]

    所以只要可以快速的求出斐波那契数列第(i)项就可以了。

    如果直接每次矩阵快速幂会(TLE)

    所以先预处理出(fbi_1,fbi_2,fbi_3...fbi_m)(fbi_m,fbi_{2m},fbi_{3m}...fbi{nm})的转移矩阵。

    对于第(i)行第(j)列的数,直接(O(2^3))求出

    代码

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #include<cstring>
    #include<bitset>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int N = 500000 + 100,INF = 1e9 + 7;
    map<ll,ll>ma;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    int C1,C2,mod,n,m,Q;
    namespace FBI {
    	struct node {
    		int a[3][3],n,m;
    		node() {
    			memset(a,0,sizeof(a));
    		}
    		node(int x) {
    			n = m = x;
    			memset(a,0,sizeof(a));
    			for(int i = 1;i <= x;++i) a[i][i] = 1;
    		}
    		node(int x,int y) {
    			n = x,m = y;
    			memset(a,0,sizeof(a));
    		}
    	};
    	node operator * (const node &A,const node &B) {
    		int n = A.n,m = B.m,K = A.m;
    		node ret(n,m);
    		for(int k = 1;k <= K;++k) {
    			for(int i = 1;i <= n;++i) {
    				for(int j = 1;j <= m;++j) {
    					ret.a[i][j] += 1ll * A.a[i][k] * B.a[k][j] % mod;
    					ret.a[i][j] %= mod;
    				}
    			}
    		}
    		return ret;
    	}
    	node fbi(1,2),tmp(2,2),lin[N],row[N];
    	void pre() {
    		fbi.a[1][1] = C2,fbi.a[1][2] = C1;
    		tmp.a[1][1] = tmp.a[1][2] = tmp.a[2][1] = 1;
    		
    		row[0].n = row[0].m = 2;row[0].a[1][1] = row[0].a[2][2] = 1;
    		for(int i = 1;i <= m;++i) row[i] = row[i - 1] * tmp;
    
    
    		lin[0].n = lin[0].m = 2;
    		lin[0].a[1][1] = lin[0].a[2][2] = 1;
    		for(int i = 1;i <= n;++i) lin[i] = lin[i - 1] * row[m];
    	}
    	int solve(ll x) {
    		if(x == -1) return (C2 - C1 + mod) % mod;
    		if(x == 0) return C1;
    		if(x == 1) return C2;
    		--x;
    		int y = x % m;
    		x /= m;
    		return (fbi * lin[x] * row[y]).a[1][1];
    	}
    	int main(ll x) {
    		return (1ll * solve(x + 1) * solve(x) % mod - 1ll * C1 * (C2 - C1) % mod + mod) % mod;
    	}
    }
    ll p(ll x,ll y) {
    	ll z = (x - 1) * m + y;
    	if(ma[z]) return ma[z];
    	return z;
    }
    ll cnt = 1,ans;
    void solve(int x,int y) {
    	++cnt;
    	if(x == n && y == m) return;
    	int down = INF,right = INF;
    	if(x != n) down = FBI::main(p(x + 1,y));
    	if(y != m) right = FBI::main(p(x,y + 1));
    	if(down <= right) {
    		ans += cnt * down % mod;
    		ans %= mod;
    		solve(x + 1,y);
    	}
    	else {
    		ans += cnt * right % mod;
    		ans %= mod;
    		solve(x,y + 1);
    	}
    	return;
    }
    int main() {
    	n = read(),m = read(),Q = read(),mod = read(),C1 = read(),C2 = read();
    	for(int i = 1;i <= Q;++i) {
    		ll x = read(),y = read(),tx = x,ty = y;
    		if(ma[x]) tx = ma[x];
    		if(ma[y]) ty = ma[y];
    		ma[x] = ty;ma[y] = tx;
    	}
    	FBI::pre();
    	if(ma[1]) ans += FBI::main(ma[1]),ans %= mod;
    	else ans += FBI::main(1),ans %= mod;
    	solve(1,1);
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    转载:C#制作PDF
    搜索研究
    HDU 4029 Distinct Submatrix [后缀数组]
    HDU 4336 Card Collector [状态压缩概率DP]
    ZOJ 3329 One Person Game [数学期望]
    POJ 2096 Collecting Bugs[数学期望]
    HDU 4338 Simple Path [双联通分量+RMQ(LCA)]
    POJ 1222 EXTENDED LIGHTS OUT [高斯消元]
    HDU 2258 Continuous Same Game (1)[模拟]
    HDU 4339 Query [树状数组]
  • 原文地址:https://www.cnblogs.com/wxyww/p/bzoj4490.html
Copyright © 2011-2022 走看看