首页 > 其他分享 >洛谷 P3321 [SDOI2015] 序列统计

洛谷 P3321 [SDOI2015] 序列统计

时间:2023-05-11 18:00:30浏览次数:51  
标签:P3321 typedef 洛谷 int res ll long maxn SDOI2015

洛谷传送门

感觉挺综合的一道题。

考虑朴素 dp,\(\forall x \in S, f_{i + 1, jx \bmod m} \gets f_{i,j}\)。复杂度 \(O(nm^2)\)。显然可以矩乘优化至 \(O(m^3 \log n)\),但是不能通过。

如果转移式中是加法而不是乘法,那很容易卷积优化。接下来是 一个很重要的套路:化乘为加。 实数范围内可以取对数,正整数范围内,考虑取 \(m\) 的原根 \(g\),因为 \(g\) 满足 \(g^0, g^1, ..., g^{m-2}\) 两两不同,所以可以把 \(1 \sim m - 1\) 的数映射到指数。

接下来求这个多项式的 \(n\) 次幂即可。注意每次倍增时要把后面的部分加到前面去,因为是在模 \(m\) 意义下。

code
// Problem: P3321 [SDOI2015]序列统计
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3321
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 32100;
const ll mod = 1004535809, G = 3;

inline ll qpow(ll b, ll p, const ll &mod) {
	ll res = 1;
	while (p) {
		if (p & 1) {
			res = res * b % mod;
		}
		b = b * b % mod;
		p >>= 1;
	}
	return res;
}

ll n, m, K, X, p, a[maxn], r[maxn], b[maxn], tot, c[maxn];

typedef vector<ll> poly;

inline poly NTT(poly a, int op) {
	int n = (int)a.size();
	for (int i = 0; i < n; ++i) {
		if (i < r[i]) {
			swap(a[i], a[r[i]]);
		}
	}
	for (int k = 1; k < n; k <<= 1) {
		ll wn = qpow(op == 1 ? G : qpow(G, mod - 2, mod), (mod - 1) / (k << 1), mod);
		for (int i = 0; i < n; i += (k << 1)) {
			ll w = 1;
			for (int j = 0; j < k; ++j, w = w * wn % mod) {
				ll x = a[i + j], y = w * a[i + j + k] % mod;
				a[i + j] = (x + y) % mod;
				a[i + j + k] = (x - y + mod) % mod;
			}
		}
	}
	return a;
}

inline poly operator * (poly a, poly b) {
	a = NTT(a, 1);
	b = NTT(b, 1);
	int n = (int)a.size();
	for (int i = 0; i < n; ++i) {
		a[i] = a[i] * b[i] % mod;
	}
	a = NTT(a, -1);
	ll inv = qpow(n, mod - 2, mod);
	for (int i = 0; i < n; ++i) {
		a[i] = a[i] * inv % mod;
	}
	return a;
}

inline bool check(ll x) {
	if (qpow(x, p, m) != 1) {
		return 0;
	}
	for (int i = 1; i <= tot; ++i) {
		if (qpow(x, p / b[i], m) == 1) {
			return 0;
		}
	}
	return 1;
}

inline poly qpow(poly a, ll m, ll p) {
	int n = (int)a.size();
	poly res(n);
	res[0] = 1;
	while (p) {
		if (p & 1) {
			res = res * a;
			for (int i = m + 1; i < n; ++i) {
				// 对 m + 1 取模
				res[i % (m + 1)] = (res[i % (m + 1)] + res[i]) % mod;
				res[i] = 0;
			}
		}
		a = a * a;
		for (int i = m + 1; i < n; ++i) {
			a[i % (m + 1)] = (a[i % (m + 1)] + a[i]) % mod;
			a[i] = 0;
		}
		p >>= 1;
	}
	return res;
}

void solve() {
	scanf("%lld%lld%lld%lld", &n, &m, &X, &K);
	p = m - 1;
	ll x = p;
	for (ll i = 2; i * i <= x; ++i) {
		if (x % i == 0) {
			b[++tot] = i;
			while (x % i == 0) {
				x /= i;
			}
		}
	}
	if (x > 1) {
		b[++tot] = x;
	}
	ll g = -1;
	for (int i = 1; i < m; ++i) {
		if (check(i)) {
			g = i;
			break;
		}
	}
	for (ll i = 0, x = 1; i <= m - 2; ++i, x = x * g % m) {
		c[x] = i;
	}
	int k = 0;
	while ((1 << k) <= m * 2) {
		++k;
	}
	for (int i = 1; i < (1 << k); ++i) {
		r[i] = (r[i >> 1] >> 1) | ((i & 1) << (k - 1));
	}
	while (K--) {
		ll x;
		scanf("%lld", &x);
		if (x % m) {
			a[c[x]] = 1;
		}
	}
	poly A;
	for (int i = 0; i < (1 << k); ++i) {
		A.pb(a[i]);
	}
	poly B = qpow(A, m - 2, n);
	printf("%lld\n", B[c[X]]);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:P3321,typedef,洛谷,int,res,ll,long,maxn,SDOI2015
From: https://www.cnblogs.com/zltzlt-blog/p/17391824.html

相关文章

  • 洛谷 P8492 - [IOI2022] 无线电信号塔
    想到将最优化问题转化为数点问题的一步了,但是因为转化的姿势不太好导致我的数点不太能用特别简洁的数据结构维护,最后只好看题解(考虑先解决单组询问的问题,对于每个点\(i\),我们找出它左边最近的\(h_l\leh_i-D\)的点\(l\),和它右边最近的\(h_r\leh_i-D\)的点\(r\),然后新建一......
  • 洛谷 P8367 - [LNOI2022] 盒(组合数学)
    设\(a\)数组的前缀和为\(s_i\),\(b\)数组的前缀和为\(t_i\),那么根据模拟费用流或者贪心的思想,每一条边经过的次数即为\(|s_i-t_i|\),因此非常trivial的做法是转换贡献体,枚举每种方案下每条边被经过的次数,然后乘以\(w_i\)求和,具体来说:\[ans=\sum\limits_{i=1}^{n-1}\sum\l......
  • 洛谷 P3369 【模板】普通平衡树
    有旋Treap模板#include<bits/stdc++.h>usingnamespacestd;structNode{ Node*ch[2]; intval,rank; intrep_cnt; intsiz; Node(intval):val(val),rep_cnt(1),siz(1){ ch[0]=ch[1]=nullptr; rank=rand(); } voidupd_siz(){ siz=......
  • 洛谷P4824题解
    题面题意:给出字符串s和t,每次操作将s中出现的第一个t删去,直到不能删为止。求最后的串。|s|<=1e6题解:hash做法。(此题也有kmp和权值线段树做法)因为涉及到删除操作,所以我们要动态的实现这个过程。所以考虑开一个栈来存储当前留下的字符。然后每有一个字符入栈,就拿当前......
  • 洛谷P7469题解
    题面题意:有两个字符串a和b,问b中有多少个本质不同子串可以由a删除若干个字符得到。|a|,|b|<=3000题解:字典树(这个题做法很多,后补)。把字符串b的每个子串打到字典树上。然后因为3000^2*26这个东西比较大,所以不能用nxt[id][26]来存储,于是使用链式前向星存图,这样tri......
  • 洛谷 P6938 - [ICPC2017 WF]Son of Pipe Stream(网络流)
    见过的最怪的网络流题,没有之一。首先新建超级源点,向\(1,2\)各连\(\infty\)的边。设最大流为\(A\),那么显然最优方案中flutter和water流量之和为\(A\)。先分析一波答案函数。显然,最终答案关于flutter的流量\(x\)的函数\(f(x)=x^a(A-x)^{1-a}\)。求导得\(f'(x)=ax^......
  • 洛谷 P7579 「RdOI R2」称重(weigh) 题解
    题意:题目一道交互题。有n个球,里面有两个假球,假球比普通球的要轻,每次可以询问任意两组球的轻重关系,第一组轻为<,第二组轻为>,一样重量为=。思路:先考虑在一个区间内找1个假球。我们可以将区间尽量平均分为3份,先询问相等的两组球的轻重关系,分3种情况:第一组轻......
  • 【做题笔记】洛谷 P7987 [USACO21DEC] Paired Up G
    在我的个人博客获得更好的阅读体验Problem洛谷P7987[USACO21DEC]PairedUpG题目大意:有\(n\)个点,其中第\(i\)个点位置为\(x_i\),权值为\(y_i\)。若两个点\(i,j\)满足\(|x_i-x_j|\lek\),则这两个点之间有一条边。求一个匹配,在满足其为极大匹配的情况下匹配点的......
  • 洛谷 P3374——树状数组 / 树状数组模板题
    洛谷P3374——树状数组#include<iostream>usingnamespacestd;constintN=5e5+10;inttr[N],a[N];intn,m;intlowbit(intx){returnx&-x;}voidadd(intu,intc){//给所有管辖中有a[i]的tr[]加上cfor(inti=u;i<=n;i+......
  • 洛谷P2241 统计方形 ,棋盘问题升级板,给出格子坐标中矩形以及正方形的计算方法
    在做这道题之前我们先了解一下棋盘问题棋盘问题(qq.com)......