zoukankan      html  css  js  c++  java
  • Frightful Formula Gym

    Problem F: Frightful Formula

    [Time Limit: 10 s quad Memory Limit: 512 MiB ]

    题意

    题意就是存在一个(n*n)的矩阵(f[n][n])。然后给出(n,a,b,c),在给出两个序列(l[n],t[n])
    定义矩阵如下:

    [egin{aligned} f[i][1] &= l[i] \ f[1][i] &= t[i] \ f[i][j] &= a*f[i][j-1] + b*f[i-1][j] + c end{aligned} ]

    求出(f[n][n]\%mod)的值。

    思路

    题目要求(f[n][n]),如果我们会求(f[n][m]),那么(f[n][n])自然也会了,下面我给出推导过程。

    1. 首先考虑(a=1, b=1, c=0)的情况

    [f[i][j] = f[i][j-1] + f[i-1][j] ]

    显然,(f[n][m])可以看成从((1,1))走到((n,m)),每一步只能向下或者向右的方案数。也就是一共要走(n+m-2)步,其中(n-1)往下走,答案就是(C_{n+m-1}^{n-1})或者(C_{n+m-1}^{m-1})
    2. 接下来考虑(a ot= 1,b ot= 1,c=0)的情况。

    [f[i][j] = a*f[i][j-1] + b*f[i-1][j] ]

    这时候每一步向右走贡献一个(a),向下走贡献一个(b)

    • 我们先考虑第一行每个点对终点的贡献,例如(f[1][i]),他到终点一共需要向右走(m-i)次,向下走(n-1)次,所以一个方案贡献了(f[1][i]*a^{m-i}b^{n-1})。那么如何计算方案数呢?为了避免重复计算,需要先向下走一步然后从(2,i)到(n,m),一共的方案数就是(C_{n+m-i-2}^{n-2})。所以对于第一行总贡献就是(sum_2^m f[1][i]*C_{n+m-i-2}^{n-2}*a^{m-i}b^{n-1})
    • 对于列来说,同样的道理,一个方案贡献了(f[i][1]*a^{m-1}b^{n-i}),然后先向右走一步防止重复计算,方案数为(C_{n+m-i-2}^{m-2})。所以第一列的总贡献就是(sum_2^nC_{n+m-i-2}^{m-2}*a^{m-1}b^{n-i})
      所以只要(O(N))遍历第一行,第一列,就能算出(f[n][m])
    • 多说一句,这样做是因为第一行、第一列的数和(f[1][1])没有关系,如果直接给出(f[1][1]),然后求(f[n][m])那么直接就可以算出答案(f[1][1]*C_{n+m-2}^{n-1}*a^{m-1}b^{n-1})
    1. 最后考虑(a ot= 1,b ot= 1,c ot=0)的情况。

    [f[i][j] = a*f[i][j-1] + b*f[i-1][j] + c ]

    如果没有(c),好做,但是有(c)怎么办呢?有没有办法把(c)去掉?
    答案是有的。
    我们令(g[i][j] = f[i][j] + k),如果存在一个(k)满足

    [g[i][j] = a*g[i][j-1] + b*g[i-1][j] ]

    那么问题就转化到了2问题去了。
    其实(k)也很好求,直接带入把(g[i][j])(f[i][j]+k)代入。

    [egin{aligned} f[i][j]+k &= a*(f[i][j-1]+k) + b*(f[i-1][j]+k)\ &= a*f[i][j-1] + b*f[i-1][j] + c end{aligned} ]

    容易得到(k = frac{c}{a+b-1} = c*inv(a+b-1)),所以做的时候把(f[1][i]、f[i][1])转化成(g[1][i]、g[i][1])求出(g[n][m]),最后在换回(f[n][m])就可以了。

    /***************************************************************
        > File Name    : F.cpp
        > Author       : Jiaaaaaaaqi
        > Created Time : 2019年05月06日 星期一 14时35分10秒
     ***************************************************************/
    
    #include <map>
    #include <set>
    #include <list>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <queue>
    #include <cfloat>
    #include <string>
    #include <vector>
    #include <cstdio>
    #include <bitset>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define  lowbit(x)  x & (-x)
    #define  mes(a, b)  memset(a, b, sizeof a)
    #define  fi         first
    #define  se         second
    #define  pii        pair<int, int>
    
    typedef unsigned long long int ull;
    typedef long long int ll;
    const int    maxn = 2e5 + 10;
    const int    maxm = 4e5 + 10;
    const ll     mod  = 1e6 + 3;
    const ll     INF  = 1e18 + 100;
    const int    inf  = 0x3f3f3f3f;
    const double pi   = acos(-1.0);
    const double eps  = 1e-8;
    using namespace std;
    
    ll n, m, a, b, c;
    int cas, tol, T;
    
    ll fac[maxm], inv[maxm];
    ll l[maxn], t[maxn];
    
    ll fpow(ll a, ll b) {
    	ll ans = 1;
    	while(b) {
    		if(b&1)	ans = ans*a%mod;
    		a = a*a%mod;
    		b >>= 1;
    	}
    	return ans;
    }
    
    void handle() {
    	fac[0] = inv[0] = 1;
    	int mx = 2*n;
    	for(int i=1; i<=mx; i++) {
    		fac[i] = fac[i-1]*i%mod;
    	}
    	inv[mx] = fpow(fac[mx], mod-2);
    	for(int i=mx-1; i>=1; i--) {
    		inv[i] = inv[i+1]*(i+1)%mod;
    	}
    }
    
    ll C(int n, int m) {
    	return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    
    int main() {
    	scanf("%lld%lld%lld%lld", &n, &a, &b, &c);
    	ll k = c*fpow(a+b-1, mod-2)%mod;
    	handle();
    	for(int i=1; i<=n; i++) {
    		scanf("%lld", &l[i]);
    		l[i] = (l[i]+k)%mod;
    	}
    	for(int i=1; i<=n; i++) {
    		scanf("%lld", &t[i]);
    		t[i] = (t[i]+k)%mod;
    	}
    	ll ans = 0ll;
    	for(int i=2; i<=n; i++) {
    		ans += l[i] * fpow(b, n-i)%mod * fpow(a, n-1)%mod * C(2*n-i-2, n-2)%mod;
    		ans %= mod;
    	}
    	for(int i=2; i<=n; i++) {
    		ans += t[i] * fpow(b, n-1)%mod * fpow(a, n-i)%mod * C(2*n-i-2, n-2)%mod;
    		ans %= mod;
    	}
    	ans = ((ans-k)%mod+mod)%mod;
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    .net core使用NLog+Elasticsearch记录日志
    .net core使用EasyNetQ做EventBus
    .net core使用Apollo做统一配置管理
    .net core使用App.Metrics+InfluxDB+Grafana进行APM监控
    .net core使用Ocelot+Identity Server统一网关验证
    .net core微服务之基于Docker+Consul+Registrator服务注册服务发现
    windows上禁止某个软件联网
    Windows修改命令行默认启动路径
    Win10对调Esc和CapsLock键
    animation模块的使用
  • 原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/10820353.html
Copyright © 2011-2022 走看看