zoukankan      html  css  js  c++  java
  • JZOJ 6833. 2020.10.24【NOIP提高A组】T3.justice(DP)

    JZOJ 6833. 2020.10.24【NOIP提高A组】T3.justice

    题目大意

    • n n n x x x m m m y y y,每次其中 k k k个合并成一个,权值变为它们的平均值,求只剩一个数的权值有多少种可能。
    • n , m , k ≤ 3000 n,m,k≤3000 n,m,k3000
    • x , y ≤ 1 0 18 x,y≤10^{18} x,y1018

    题解

    • 如果 x = y x=y x=y,那么答案是 1 1 1,否则显然 x x x y y y无论是多少,答案都只和 n , m , k n,m,k n,m,k有关。
    • 直接令 x = 0 , y = 1 x=0,y=1 x=0,y=1,考虑把初始的 n + m n+m n+m个数放在一棵 k k k叉树上, 0 0 0对最后权值的贡献是 0 0 0 1 1 1对最后权值的贡献就是 ( 1 k ) d e e p (frac{1}{k})^{deep} (k1)deep,其中 d e e p deep deep为这个数的深度。
    • 那么最后的数就是 V = ∑ ( 1 k ) d e e p V=sum(frac{1}{k})^{deep} V=(k1)deep,可以理解为是一个 k k k进制下的小数,
    • 如果没有进位,那这个数小数部分数位之和 S = m S=m S=m,每进位一次 S S S就要减去 k − 1 k-1 k1,所以 S ≡ m ( m o d k − 1 ) Sequiv mpmod {k-1} Sm(modk1),且 S ≤ m S≤m Sm.
    • 在某种操作方式下,如果把 0 0 0 1 1 1交换,那么 1 − V 1-V 1V表示成的 k k k进制数数位之和 S ′ S' S就应该满足 S ′ ≡ n ( m o d k − 1 ) S'equiv npmod {k-1} Sn(modk1),且 S ≤ n S≤n Sn.
    • 而此时的 S ′ S' S是可以通过 S S S计算出来的,若这个小数位数为 l l l,则 S ′ = ( l − 1 ) ∗ ( k − 1 ) + k − S S'=(l-1)*(k-1)+k-S S=(l1)(k1)+kS,类似于 1.000 … 1.000… 1.000减去某个数列竖式减法。
    • 这样就相当于要构造一个 k k k进制小数,满足数位和为 S S S S S S满足上面的限制, S S S对应的 S ′ S' S也要满足上面的限制,求方案数。
    • f i , j f_{i,j} fi,j表示前 i i i位和为 j j j的方案数, O ( n ) O(n) O(n)转移,总复杂度 O ( n 3 ) O(n^3) O(n3),用前缀和可以优化到 O ( n 2 ) O(n^2) O(n2)

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define md 1000000007
    #define ll long long 
    #define N 3010
    ll f[N * 2][N][2], g[N];
    int main() {
    	int n, m, k, i, j; ll x, y;
    	scanf("%d%d%d%lld%lld", &m, &n, &k, &x, &y);
    	f[0][0][0] = 1;
    	for(i = 1; i <= (n + m) / (k - 1); i++) {
    		g[0] = (f[i - 1][0][0] + f[i - 1][0][1]) % md;
    		for(j = 1; j <= n; j++) g[j] = (g[j - 1] + f[i - 1][j][0] + f[i - 1][j][1]) % md;
    		for(j = 0; j <= n; j++) {
    			if(j) {
    				if(j - k < 0) f[i][j][1] = g[j - 1];
    				else f[i][j][1] = (g[j - 1] - g[j - k] + md) % md;	
    			}
    			f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1]) % md;
    		}
    	}
    	ll ans = 0;
    	for(i = 0; i <= (n + m) / (k - 1); i++) {
    		for(j = 0; j <= n; j++) 
    			if(j % (k - 1) == n % (k - 1) && i * (k - 1) - j + 1 <= m) (ans += f[i][j][1]) %= md;
    	}
    	if(x == y) ans = 1;
    	printf("%lld
    ", ans);
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    your account already has a valid ios distribution certificate
    uinavigation样式
    phonegap ios默认启动页
    git init出错
    ios assetlibrary
    uitableviewcell高度自适应笔记
    ios frame bounds applicationframe
    java学习笔记
    file not found while xcode archive
    c++回调
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910015.html
Copyright © 2011-2022 走看看