zoukankan      html  css  js  c++  java
  • 题解 P3321 【[SDOI2015]序列统计】

    题目链接

    Solution [SDOI2015]序列统计

    题目大意:给定一个集合 (S),求生成一个长为 (n) ,每个元素属于 (S),所有元素积 (mod;m=x) 的数列的方案数。(m) 为质数。

    原根,NTT


    分析:首先我们想办法把乘法变为加法,这样我们就可以用卷积来计算了。

    特判掉 (S) 中有 (0) 的情况。

    由于 (m) 为质数,所以它一定有原根,因而乘法群可以变为加法群,乘法在 (mod;m) 意义下运算,加法在 (mod;varphi(m)=m-1) 意义下运算。

    问题转换为给定一个多项式,求它的 (n) 次幂中,所有指数 (mod;(m-1)) 同余于 (ln(x)) 的系数和。

    对快速幂进行些许修改即可。两个 (m-2) 次多项式相乘,将 (m-1) 项以及之后的系数累加给前面(0-(m-2))

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <vector>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    using namespace std;
    typedef long long ll;
    constexpr int maxn = 1e5,mod = 1004535809,G = 3,invG = 334845270,inf = 0x7fffffff;
    constexpr int add(const int a,const int b,const int mod = ::mod){return (a + b) % mod;}
    constexpr int sub(const int a,const int b,const int mod = ::mod){return (a - b + mod) % mod;}
    constexpr int mul(const int a,const int b,const int mod = ::mod){return (1ll * a * b) % mod;}
    constexpr int qpow(int base,int b,const int mod = ::mod){//-std=c++17
    	int res = 1;
    	while(b){
    		if(b & 1)res = mul(res,base,mod);
    		base = mul(base,base,mod);
    		b >>= 1;
    	}
    	return res;
    }
    constexpr int inv(const int x,const int mod = ::mod){return qpow(x,mod - 2,mod);}//-std=c++17
    constexpr int calc(const int a,const int b,const int mod = ::mod){return mul(a,inv(b,mod),mod);}
    struct IO{//-std=c++11,with cstdio and cctype
    	private:
    		static constexpr int ibufsiz = 1 << 20;
    		char ibuf[ibufsiz + 1],*inow = ibuf,*ied = ibuf;
    		static constexpr int obufsiz = 1 << 20;
    		char obuf[obufsiz + 1],*onow = obuf;
    		const char *oed = obuf + obufsiz;
    	public:
    		char getchar(){
    			#ifndef ONLINE_JUDGE
    				return ::getchar();
    			#else
    				if(inow == ied){
    					ied = ibuf + sizeof(char) * fread(ibuf,sizeof(char),ibufsiz,stdin);
    					*ied = '';
    					inow = ibuf;
    				}
    				return *inow++;
    			#endif
    		}
    		template<typename T>
    		void read(T &x){
    			static bool flg;flg = 0;
    			x = 0;char c = getchar();
    			while(!isdigit(c))flg = c == '-' ? 1 : flg,c = getchar();
    			while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    			if(flg)x = -x;
    		}
    		template <typename T,typename ...Y>
    		void read(T &x,Y&... X){read(x);read(X...);}
    		int readi(){static int res;read(res);return res;}
    		long long readll(){static long long res;read(res);return res;}
    		
    		void flush(){
    			fwrite(obuf,sizeof(char),onow - obuf,stdout);
    			fflush(stdout);
    			onow = obuf;
    		}
    		void putchar(char c){
    			#ifndef ONLINE_JUDGE
    				::putchar(c);
    			#else
    				*onow++ = c;
    				if(onow == oed){
    					fwrite(obuf,sizeof(char),obufsiz,stdout);
    					onow = obuf;
    				}
    			#endif
    		}
    		template <typename T>
    		void write(T x,char split = ''){
    			static unsigned char buf[64];
    			if(x < 0)putchar('-'),x = -x;
    			int p = 0;
    			do{
    				buf[++p] = x % 10;
    				x /= 10;
    			}while(x);
    			for(int i = p;i >= 1;i--)putchar(buf[i] + '0');
    			if(split != '')putchar(split);
    		}
    		void lf(){putchar('
    ');}
    		~IO(){
    			fwrite(obuf,sizeof(char),onow - obuf,stdout);
    		}
    }io;
    
    int tr[maxn],len;
    void gettr(const int x){
    	for(len = 1;len < x;len <<= 1);
    	for(int i = 1;i < len;i++)tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (len >> 1) : 0);
    }
    struct poly : std::vector<int>{
    	using std::vector<int>::vector;
    	#define f (*this)
    	void ntt(const int flg = 1){
    		const int n = size();
    		for(int i = 0;i < n;i++)
    			if(i < tr[i])std::swap(f[i],f[tr[i]]);
    		for(int p = 2;p <= n;p <<= 1){
    			const int len = p >> 1;
    			const int unit = qpow(flg == 1 ? G : invG,(mod - 1) / p);
    			for(int k = 0;k < n;k += p){
    				int now = 1;
    				for(int l = k;l < k + len;l++){
    					const int tt = mul(f[l + len],now);
    					f[l + len] = sub(f[l],tt);
    					f[l] = add(f[l],tt);
    					now = mul(now,unit);
    				}
    			}
    		}
    		if(flg == -1){
    			const int inv = ::inv(n);
    			for(int i = 0;i < n;i++)f[i] = mul(f[i],inv);
    		}
    	}
    	poly operator * (const poly &g)const{
    		poly res(size());
    		for(unsigned int i = 0;i < size();i++)res[i] = mul(f[i],g[i]);
    		return res;
    	}
    	poly operator + (const poly &g)const{
    		poly res(size());
    		for(unsigned int i = 0;i < size();i++)res[i] = add(f[i],g[i]);
    		return res;
    	}
    	#undef f
    };
    namespace getg{
    	constexpr int maxn = 1e4;
    	int fac[maxn];
    	void sieve(){
    		static bool vis[maxn];
    		static vector<int> pri;
    		for(int i = 2;i < maxn;i++){
    			if(!vis[i]){
    				pri.push_back(i);
    				fac[i] = i;
    			}
    			for(int x : pri){
    				if(1ll * x * i >= maxn)break;
    				vis[x * i] = 1;
    				fac[x * i] = x;
    				if(i % x == 0)break;
    			}
    		}
    	}
    	int solve(const int p){
    		static auto chk = [&](const int g){
    			int now = p - 1;
    			while(now != 1){
    				if(qpow(g,(p - 1) / fac[now],p) == 1)return false;
    				now /= fac[now];
    			}
    			return true;
    		};
    		for(int i = 2;;i++)
    			if(chk(i))return i;
    		return -1;
    	}
    }
    poly trans;
    int n,m,x,siz,g,ln[maxn],exp[maxn];
    poly qpow(poly base,int b){
    	gettr((m - 1) << 1);
    	poly res(m - 1);res[0] = 1;
    	while(b){
    		if(b & 1){
    			res.resize(len),base.resize(len);
    			res.ntt(),base.ntt();
    			res = res * base;
    			res.ntt(-1),base.ntt(-1);
    			for(int i = 0;i < m - 2;i++)res[i] = add(res[i],res[i + m - 1]);
    			res.resize(m - 1),base.resize(m - 1);
    		}
    		base.resize(len);
    		base.ntt();
    		base = base * base;
    		base.ntt(-1);
    		for(int i = 0;i < m - 2;i++)base[i] = add(base[i],base[i + m - 1]);
    		base.resize(m - 1);
    		b >>= 1;
    	}
    	return res;
    }
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("fafa.in","r",stdin);
    #endif
    	getg::sieve();
    	io.read(n,m,x,siz);
    	g = getg::solve(m);
    	exp[0] = 1;
    	for(int i = 1;i <= m - 1;i++)exp[i] = mul(exp[i - 1],g,m);
    	for(int i = 0;i < m - 1;i++)ln[exp[i]] = i;
    	trans.resize(m - 1);
    	for(int x,i = 1;i <= siz;i++){
    		io.read(x);
    		if(x)trans[ln[x]]++;
    		else if(!::x){
    			io.write(sub(qpow(siz,n),qpow(siz - 1,n)),'
    ');
    			return 0;
    		}
    	}
    	poly &&ans = qpow(trans,n);
    	io.write(ans[ln[x]],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    后缀表达式
    约瑟夫环
    能手进阶:Linux操作琐细驱动编译与运转
    VLC 0.8.5
    Gimpshop 2.2.11
    Blender 2.42
    有助于数据确立平安环境的次要效率阐明');
    DivFix 0.20
    Ubuntu Dapper 提速脚本
    你值得知道的五佳非主流阅读器
  • 原文地址:https://www.cnblogs.com/colazcy/p/14247398.html
Copyright © 2011-2022 走看看