• 【洛谷】P2000 拯救世界


    题解

    小迪的blog : https://www.cnblogs.com/RabbitHu/p/9178645.html
    请大家点推荐并在sigongzi的评论下面点支持谢谢!

    掌握了小迪生成函数的有趣姿势之后,我们考虑一下这个问题

    由于出题人语死早,我们认为是十种石头的生成函数直接乘起来

    (frac{1}{1 - x^6} cdot frac{1 - x^{10}}{1 - x} cdot frac{1 - x^{5}}{1 - x} cdot frac{1}{1 - x^4} cdot frac{1 - x^8}{1 - x} cdot frac{1}{1 - x^2} cdot frac{1 - x^2}{1 - x} cdot frac{1}{1 - x^8} cdot frac{1}{1 - x^10} cdot frac{1 - x^4}{1 - x} = frac{1}{(1 - x)^5})
    这个正好是上面那个blog里和组合数有关的生成函数,所以我们要求的值就是
    (inom{n + 5 - 1}{5 - 1} = inom{n + 4}{4} = frac{(n + 1)(n + 2)(n + 3)(n + 4)}{24})
    显然需要高精度了,还得是FFT
    可以用NTT代替(因为值不会太大)

    “我司嘉祺就算是TLE死,死外面,从这里跳下去,也绝对不会开O2的!”
    “氧气真好吸。”

    代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define MAXN 1000005
    //#define ivorysi
    #define pb push_back
    using namespace std;
    typedef long long int64;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    const int MOD = 998244353,MaxL = (1 << 20); 
    int W[(1 << 20) + 5],N;
    char a[1000005];
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    int fpow(int x,int c) {
        int res = 1,t = x;
        while(c) {
    	if(c & 1) res = mul(res,t);
    	t = mul(t,t);
    	c >>= 1;
        }
        return res;
    }
    struct Bignum {
        vector<int> v;
        friend Bignum operator + (const Bignum &a,const int &x) {
    	Bignum c;c.v.clear();
    	int g = (a.v[0] + x) / 10;
    	c.v.pb((a.v[0] + x) % 10);
    	for(int i = 1 ; i < a.v.size() ; ++i) {
    	    int t = a.v[i] + g;
    	    c.v.pb(t % 10);g = t / 10;
    	}
    	if(g) c.v.pb(g);
    	return c;
        }
        friend void NTT(Bignum &f,int LEN,int on) {
    	f.v.resize(LEN);
    	for(int i = 1 , j = LEN / 2 ; i < LEN - 1 ; ++i) {
    	    if(i < j) swap(f.v[i],f.v[j]);
    	    int k = LEN / 2;
    	    while(j >= k) {
    		j -= k;
    		k >>= 1;
    	    }
    	    j += k;
    	}
    	for(int h = 2 ; h <= LEN ; h <<= 1) {
    	    int wn = W[(MaxL + on * MaxL / h) % MaxL];
    	    for(int k = 0 ; k < LEN ; k += h) {
    		int w = 1;
    		for(int j = k ; j < k + h / 2 ; ++j) {
    		    int u = f.v[j],t = mul(w,f.v[j + h / 2]);
    		    f.v[j] = inc(u,t);
    		    f.v[j + h / 2] = inc(u,MOD - t);
    		    w = mul(w,wn);
    		}
    	    }
    	}
    	if(on == -1) {
    	    int InvL = fpow(LEN,MOD - 2);
    	    for(int i = 0 ; i < LEN ; ++i) f.v[i] = mul(f.v[i],InvL);
    	}
        }
        friend Bignum operator * (Bignum a,Bignum b) {
    	int s = a.v.size() + b.v.size() - 2,t = 1;
    	while(t <= s) t <<= 1;
    	NTT(a,t,1);NTT(b,t,1);
    	Bignum c;c.v.clear();
    	for(int i = 0 ; i < t ; ++i) c.v.pb(mul(a.v[i],b.v[i]));
    	NTT(c,t,-1);
    	int64 x = 0;
    	for(int i = 0 ; i < t ; ++i) {
    	    x += c.v[i];
    	    c.v[i] = x % 10;
    	    x /= 10;
    	}
    	while(x) {
    	    c.v.pb(x % 10);
    	    x /= 10;
    	}
    	for(int i = c.v.size() - 1 ; i > 0 ; --i) {
    	    if(c.v[i] == 0) c.v.pop_back();
    	    else break;
    	}
    	return c;
        }
        friend Bignum operator / (const Bignum &a,int k) {
    	Bignum c;c.v.clear();c.v.resize(a.v.size());
    	int x = 0;
    	for(int i = a.v.size() - 1 ; i >= 0 ; --i) {
    	    x = x * 10 + a.v[i];
    	    c.v[i] = x / k;
    	    x %= k;
    	}
    	for(int i = a.v.size() - 1 ; i > 0 ; --i) {
    	    if(c.v[i] == 0) c.v.pop_back();
    	    else break;
    	}
    	return c;
        }
        void print() {
    	for(int i = v.size() - 1 ; i >= 0 ; --i) {
    	    putchar('0' + v[i]);
    	}
        }
    }A,B;
    void Solve() {
        W[0] = 1;W[1] = fpow(3,(MOD - 1) / (1 << 20));
        for(int i = 2 ; i < (1 << 20) ; ++i) W[i] = mul(W[i - 1],W[1]);
        scanf("%s",a + 1);
        N = strlen(a + 1);
        A.v.clear();
        for(int i = N ; i >= 1 ; --i) A.v.pb(a[i] - '0');
        B = ((A + 1) * (A + 2)) * ((A + 3) * (A + 4));
        B = B / 24;
        B.print();enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    
  • 相关阅读:
    MutationObserverAPI--微任务
    Promise.then方法的执行顺序例题分析
    遍历器Iterator--指针对象
    最实用的数组去重方法
    【JavaScript】允许IE8使用placeholder
    【JavaScript】创建命名空间,Class,LOG
    【JavaScript】JavaScript模拟Class
    【Java】PrettyTime
    【JavaScript】日期和数字格式化
    前端开发总结
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9179680.html
Copyright © 2020-2023  润新知