ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Easy Sum

2022-06-25 11:02:30  阅读:166  来源: 互联网

标签:return cur int Sum ++ Easy include define


Link

\(n^2\) 暴力很好想,但我们先找到一种常数小的 \(n^2\) 做法。

考虑组合意义,这种 \(a_i , b_i\) 的形式很容易让人联想到网格图的路径方案数。

于是令 \(f_{a_i,b_i} = 1\) 为初始状态,\(f_{i,j} = f_{i + 1 , j} + f_{i , j + 1}\)。

那么 \(f_{0,k}\) 就是我们的答案。由于只有加法,常数很小,所以可以跑 40pts。

由于答案最后是分布在一列上,我们不妨用生成函数来考虑这件事。我们把一列的 dp 值写成一个生成函数,转移一列就相当于滚了一次前缀和。

滚前缀和相当于乘了一个 \(T(x) = \frac{1}{1 - x}\)(封闭形式)。

但我们还需要在滚前缀和过程中在个别位置加上 \(1\) 作为初始值。由于每个 \(T(x)\) 的长度是 \(O(n)\) 的,因此直接加很不方便。

考虑分块,设块长大小为 \(B\)。则我们每次滚 \(B\) 次前缀和,即每次乘以 \(T^B(x)\)。但这 \(B\) 列中可能还有一些计算点,这些计算点到我们新的当前列可能只需要乘以 \(T^{B - d}(x)\)。

因此我们把这个点值乘以 \((1 - x)^d\) 加到我们滚 \(B\) 次前缀和的多项式上面就好了。注意到 \(d < B\) ,所以总复杂度为 \(O(\frac{n}{B} n \log n + nB)\)。

所以,\(B = \sqrt{n \log n}\) 时最优。

由于是多项式题,所以常数巨大。

#include <map>
#include <set>
#include <ctime>
#include <queue>
#include <cmath>
#include <bitset>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define pii pair <int , int>
#define pll pair <LL , LL>
#define mp make_pair
#define fs first
#define sc second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

//const int Mxdt=100000; 
//static char buf[Mxdt],*p1=buf,*p2=buf;
//#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;

template <typename T>
void read(T &x) {
	T f=1;x=0;char s=getchar();
	while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
	while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s-'0');s=getchar();}
	x *= f;
}

template <typename T>
void write(T x , char s='\n') {
	if(!x) {putchar('0');putchar(s);return;}
	if(x<0) {putchar('-');x=-x;}
	T tmp[25]={},t=0;
	while(x) tmp[t++]=x%10,x/=10;
	while(t-->0) putchar(tmp[t]+'0');
	putchar(s); 
}

#define poly vector <int>
#define Len(x) (int)x.size()

const int MAXN = 1e5 + 5;
const int B = 1414;
//const int B = 1;
const int mod = 998244353;

inline int Add(int x , int y) {x += y;return x > mod?x - mod:x;}
inline int Mul(int x , int y) {return 1ll * x * y % mod;}
inline int Sub(int x , int y) {x -= y;return x < 0?x + mod:x;}

vector <int> P[MAXN];

int qpow(int a , int b) {
	int res = 1;
	while(b) {
		if(b & 1) res = Mul(res , a);
		a = Mul(a , a);
		b >>= 1;
	}
	return res;
}

int r[MAXN << 2];
void NTT(poly &F , int op) {
	for (int i = 0; i < Len(F); ++i) if(i < r[i]) swap(F[i] , F[r[i]]);
	for (int k = 1 , t = 1; k < Len(F); k <<= 1 , t ++) {
		int ori = qpow(114514 , (op == 1)?(mod - 1) / (k << 1):(mod - 1) - (mod - 1) / (k << 1));
		for (int i = 0; i < (Len(F) >> t); ++i) {
			int now = 1;
			for (int j = 0; j < k; ++j) {
				int cur = Mul(F[(i << t) ^ j ^ k] , now);
				F[(i << t) ^ j ^ k] = Sub(F[(i << t) ^ j] , cur);
				F[(i << t) ^ j] = Add(F[(i << t) ^ j] , cur);
				now = Mul(now , ori);
			}
		}
	}
	if(op == -1) {
		int D = qpow(Len(F) , mod - 2);
		for (int i = 0; i < Len(F); ++i) F[i] = Mul(F[i] , D);
	}
}

poly operator * (poly F , poly G) {
	poly FG;
	int rl = Len(F) + Len(G) - 1 , n = Len(F) , m = Len(G) , N = 1;
	while(N <= rl) N <<= 1; 
	FG.resize(N) , F.resize(N) , G.resize(N);
	for (int i = 0; i < N; ++i) {
		r[i] = (r[i >> 1] >> 1) | ((i & 1)?(N >> 1):0);
		FG[i] = 0;
		if(i >= n) F[i] = 0;
		if(i >= m) G[i] = 0;
	}
	NTT(F , 1) , NTT(G , 1);
	for (int i = 0; i < N; ++i) FG[i] = Mul(F[i] , G[i]);
	NTT(FG , -1);
	FG.resize(rl);
	return FG;
}

int n , a[MAXN] , b[MAXN];
int fac[MAXN << 1] , finv[MAXN << 1];

int C(int n , int m) {
	return Mul(fac[n] , Mul(finv[n - m] , finv[m]));
}

poly Make_poly(int n , int B) {
	poly res;res.resize(n);
	for (int i = 0; i < n; ++i) res[i] = C(i + B - 1 , B - 1);
	return res;
}

poly ot , t , s[B + 5];

int main() {
	read(n);
	for (int i = 1; i <= n; ++i) read(a[i]) , read(b[i]) , P[a[i]].push_back(b[i]);
	fac[0] = 1;
	for (int i = 1; i <= n * 2; ++i) fac[i] = Mul(fac[i - 1] , i);
	finv[n * 2] = qpow(fac[n * 2] , mod - 2);
	for (int i = n * 2; i >= 1; --i) finv[i - 1] = Mul(finv[i] , i);
	
//	ot.reserve(n + 1);
//	for (int i = 0; i <= n; ++i) ot.push_back(1);
	t = Make_poly(n , B);
//	for (int i = 0; i <= n; ++i) write(t[i] , ' ');puts("");
	s[0].push_back(1);
	s[1].push_back(1) , s[1].push_back(Sub(0 , 1));
	for (int i = 2; i <= B + 1; ++i) s[i] = s[i / 2] * s[(i + 1) / 2];
	
	poly cur;cur.resize(n);
	for (int i = n - 1; i >= 0; i -= B) {
		for (int j = i; j >= max(i - B + 1 , 0); --j) {
			for (auto p:P[j]) {
				int bg = n - p - 1;
				for (int k = 0; k < Len(s[i - j]) && k + bg < n; ++k) {
					cur[k + bg] = Add(cur[k + bg] , s[i - j][k]);
				}
			}
		}
		if(i >= B) cur = cur * t;
		else cur = cur * Make_poly(n , i + 1);
		cur.resize(n);
//		for (int i = 0; i < n; ++i) write(cur[i] , ' ');puts("");
	}
	
	for (int i = n - 1; i >= 0; --i) write(cur[i] , ' ');
	
	return 0;
}

标签:return,cur,int,Sum,++,Easy,include,define
来源: https://www.cnblogs.com/Reanap/p/16410907.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有