首页 > 其他分享 >P3200 [HNOI2009] 有趣的数列

P3200 [HNOI2009] 有趣的数列

时间:2023-09-14 14:46:59浏览次数:44  
标签:数列 int ll catalan void P3200 HNOI2009 我们 define

原题

这题我\(O(n^2)\)的做法竟然没有想出来,反思QwQ

首先\(O(n^2)\)的做法很好想,我们考虑从小到大往数组里填数,显然我们要求任何时刻编号为奇数的位置要填的比编号为偶数的位置要不少才行

于是我们设\(dp_{i,j,k}\)表示填了前\(i\)个数,奇数位填的个数为\(j\),偶数位填的个数为\(k\)。首先我们先不说转移,可以发现\(k = i - j\),于是我们把\(k\)这一位省掉

于是我们有转移:

\[dp_{i,j} = \begin{cases} dp_{i-1,j}+dp_{i-1,j-1} & (j>k) \\ dp_{i-1,j} & (j = k) \end{cases} \]

于是我们拿到了\(50pts\)


我们要怎么发现这个东西是\(catalan\)数呢?我们看这个限制:

任何时刻编号为奇数的位置要填的比编号为偶数的位置要不少

我们可以发现catalan数就是用来求这种限制的。因为我们考虑一种思考方式:我们从\((0,0) \rightarrow (2n,0)\),如果是放到奇数位就向右上走,放到偶数位向右下走,不得碰到\(x\)轴以下的方案数,这个很明显是catalan数,因此最终答案就是第\(n\)个catalan数

完结撒花……

我们发现我们开香槟开早了,因为\(p\)不是一个质数,我们不太好计算答案

我们发现catalan数有\(\large{ C_n = \frac{\binom{2n}{n}}{n+1} = \frac{\prod_{i=n+2}^{2n}{i}}{n!} }\),因此我们可以用素数筛出前\(2n\)个数的最小质因子,并把所有数质因数分解后再计算,这么做是\(O(n \log n)\)的

但其实我们可以优化一下,就是开一个桶记录某一个质因子的个数,每次向最小质因子和剩下的部分转移,可以做到\(O(n)\)(这里我知道我表达的很烂,因此给出代码)

#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define pcn putchar('\n')
#define ll long long
#define LL __int128
#define MP make_pair
#define fi first
#define se second
#define gsize(x) ((int)(x).size())
#define Min(a, b) (a = min(a, b))
#define Max(a, b) (a = max(a, b))
#define For(i, j, k) for(int i = (j), END##i = (k); i <= END##i; ++ i)
#define For__(i, j, k) for(int i = (j), END##i = (k); i >= END##i; -- i)
#define Fore(i, j, k) for(int i = (j); i; i = (k))
//#define random(l, r) ((ll)(rnd() % (r - l + 1)) + l)
using namespace std;

namespace IO {
	template <typename T> T read(T &num){
	    num = 0; T f = 1; char c = ' '; while(c < 48 || c > 57) if((c = getchar()) == '-') f = -1;
	    while(c >= 48 && c <= 57) num = (num << 1) + (num << 3) + (c ^ 48), c = getchar();
	    return num *= f;
	}
	ll read(){
	    ll num = 0, f = 1; char c = ' '; while(c < 48 || c > 57) if((c = getchar()) == '-') f = -1;
	    while(c >= 48 && c <= 57) num = (num << 1) + (num << 3) + (c ^ 48), c = getchar();
	    return num * f;
	}
	template <typename T> void Write(T x){
	    if(x < 0) putchar('-'), x = -x; if(x == 0){putchar('0'); return ;}
	    if(x > 9) Write(x / 10); putchar('0' + x % 10); return ;
	}
	void putc(string s){ int len = s.size() - 1; For(i, 0, len) putchar(s[ i ]); }
	template <typename T> void write(T x, string s = "\0"){ Write( x ), putc( s ); }
}
using namespace IO;

/* ====================================== */

const int maxn = 2e6 + 50;

int n;
ll mod;
int prime[ maxn >> 3 ], cntp;
int minp[ maxn ];
int cnt[ maxn ];

void GetPrime(int n){
	For(i, 2, n){
		if(!minp[ i ]){
			prime[ ++ cntp ] = i;
			minp[ i ] = i;
		}
		For(j, 1, cntp){
			static int x; x = i * prime[ j ];
			if(x > n) break;
			minp[ x ] = prime[ j ];
			if(i % prime[ j ] == 0) break;
		}
	}
}

ll power(ll a, ll b){
	ll ans = 1;
	while(b){
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}

void mian(){
	read(n), read(mod);
	GetPrime(n << 1);
	For(i, 2, n) cnt[ i ] = -1; // 作为除法
	For(i, n + 2, n << 1) cnt[ i ] = 1; // 作为乘法
	For__(i, n << 1, 2){
		if(minp[ i ] < i){ // 向最小质因子和剩下部分转移
			cnt[ minp[ i ] ] += cnt[ i ];
			cnt[ i / minp[ i ] ] += cnt[ i ];
			cnt[ i ] = 0;
		}
	}
	ll ans = 1;
	For(i, 2, n << 1){
		if(minp[ i ] == i){
			ans = ans * power(i, cnt[ i ]) % mod; // 计算答案
		}
	}
	write(ans, "\n"); 
}

void init(){

}

int main() {

#ifdef ONLINE_JUDGE
#else
	freopen("data.in", "r", stdin);
//	freopen("data.out", "w", stdout);
#endif

	int T = 1;
//	read(T);
	while(T --){
		init();
		mian();
	}

	return 0;
}

标签:数列,int,ll,catalan,void,P3200,HNOI2009,我们,define
From: https://www.cnblogs.com/fox-konata/p/17702421.html

相关文章

  • P3201 [HNOI2009] 梦幻布丁 启发式合并,时间复杂度
    [HNOI2009]梦幻布丁一种很暴力,很容易想到,但时间复杂度不对的做法:既然每一次修改是以颜色作为单位的,那就用set或者链表(vector)维护每一个颜色出现的位置。将颜色\(x\)改为\(y\)的时候,遍历\(list_x\)的每一个点,判断其左右是否为\(y\),更新ans(不同颜色块数量)时间复杂度最大为......
  • 复习 - 斐波那契数列
    斐波那契数列(Fibonaccisequence)前言:斐波那契数列是最基础最常见的了,但是隔很久不仅是对语言,对这个也开始生疏了。这里做一次复习并用几种常用语言来实现。又称黄金分割数列、因数学家莱昂纳多·斐波那契(LeonardodaFibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的......
  • #yyds干货盘点# LeetCode程序员面试金典:等差数列划分
    1.简述:如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。子数组 是数组中的一个连续序列。 示例1......
  • 斐波那契数列
    1描述:这里用Js数组模拟数列。letfn=[];  fn[0]=1;  fn[1]=1;  fn[2]=2----------fn[0]+fn[1];fn[3]=3----------fn[1]+fn[2];这样子:fn=[1,1,2,3,5];设fn的索引为n; 问n==100时候。fn[n]的值。 functiongen_feiblo(num){letinit_arr=[1,1];for(leti=......
  • 代码随想录算法训练营第二天| 977.有序数组的平方,209.长度最小的子数列,59.螺旋矩阵Ⅱ
    977.有序数组的平方双指针法因为负数平方后也会变大,所以较大的平方值只可能在靠近两端的位置,越往中间走平方值必定越小。所以,在原数组两端各定义一个指针,慢慢往中间走,然后把平方值按顺序放到新数组里即可。classSolution{public:vector<int>sortedSquares(vector<i......
  • P4729 [HNOI2009] 积木游戏
    P4729[HNOI2009]积木游戏Solution2023.09.06。八个月前做这个题调了六个小时。现在看来,除开欧拉定理的部分,整道题的思路极其清晰易懂,虽然码量大,但并不难码。尽管如此,融合了数据结构、图论(模型构建+三元环计数)、拓扑论(欧拉定理)多方面知识点,而且还有四面共角的细节问题,它仍然......
  • 【算法】斐波那契数列与台风的故事
    在小岛的一个海滨小镇上,住着一个名叫苏菲的女孩。苏菲一家人靠海为生,她的生活简单而朴素,与大自然和谐共生。每天,苏菲都会来到海边,欣赏那美丽的日出和日落,感受着大海的呼吸。然而,小岛的美丽风光并非一成不变。每年夏季,热带气旋活跃,台风频繁登陆,给小岛带来了严重的危害。有一天,苏......
  • 通过c语言来实现斐波那契数列
    斐波那契数列是一组第一位和第二位为1,从第三位开始,后一位是前两位和的一组递增数列,像这样的:0、1、1、2、3、5、8、13、21、34、55......这个数列从第3项开始,每一项都等于前两项之和。以下通过c语言来实现这个程序#include<stdio.h>//1123581321345589intmain(){ /......
  • P5175 数列
    Updated2023.07.05修正了一处笔误,在此感谢@DWT8125题解首先先推一下柿子,因为数据范围很大,所以考虑矩阵加速递推。根据题意给的递推式,可得:\[\begin{aligned}a_i^2 &=(x\timesa_{i-1}+y\timesa_{i-2})^2\\ &=x^2\timesa_{i-1}^2+y^2\timesa_{i-2}^2+2xy\timesa_{......
  • §3. 数列极限存在的条件
    掌握单调有界原理、致密性定理、柯西收敛准则,能够运用这些定理证明一个数列是否收敛。 设S为有界数集,则若,则存在严格递减数列,使得数列发散的充要条件是:存在,对任意的正整数N,总存在,使得重点习题:1、3(单调有界原理)、5-8.......