1. 程式人生 > 其它 >2022五一爆零記總結二

2022五一爆零記總結二

五一第三天 ,被關在學校不能出去玩QAQ
第一題結論推炸了,打表看到1、2、5該想到是卡特蘭數的
第二題想到過分塊但是覺得太麻煩於是就沒有打誒嘿
第三題題目做法是推出來了的,容斥DFS寫炸最後竟然還有20分


第一題 數列

題面在下面啦(點選檢視)

點選檢視程式碼
數列(sequence.c/cpp/pas)
1 題目描述
我們稱一個長度為 2n 的數列是有趣的,當且僅當該數列滿足以下三個條件:
 (1)它是從 1 到 2n 共 2n 個整數的一個排列{ai};
 (2)所有的奇數項滿足 a1<a3<…<a2n-1,所有的偶數項滿足 a2<a4<…<a2n;
 (3)任意相鄰的兩項 a2i-1與 a2i(1≤i≤n)滿足奇數項小於偶數項,即:a2i-1<a2i。
 現在的任務是:對於給定的 n,請求出有多少個不同的長度為 2n 的有趣的數列。因為
最後的答案可能很大,所以只要求輸出答案 mod P 的值。
2 輸入格式
輸入檔案只包含用空格隔開的兩個整數 n 和 P。
3 輸出格式
僅含一個整數,表示不同的長度為 2n 的有趣的數列個數 mod P 的值。
4 樣例輸入
  3 6
5 樣例輸出
  5
6 資料範圍與約定
 對於 30%的資料滿足 n≤1000;
 對於另外 30%的資料滿足 P 為質數;
 對於 100%的資料滿足 n≤1000000 且 P≤1000000000。

程式碼如下

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int f=1,j=0;char w=getchar();
	while(w>'9'||w<'0'){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(w>='0'&&w<='9'){
		j=(j<<3)+(j<<1)+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=2000001;
bool use[N];
int zhi[N],f[N],tail,n,mod;
int sumi(int sum,int num){
	long long ansn=1,nown=sum;
	while(num>0){
		if(num&1)ansn=ansn*nown%mod;
		num/=2;
		nown=nown*nown%mod;
	}
	return ansn;
}
signed main(){
	//freopen("sequence.in","r",stdin);
	//freopen("sequence.out","w",stdout);
	n=read();mod=read();
	for(int i=2;i<=n*2;i++){
		if(!use[i])zhi[++tail]=i;
		for(int u=1;u<=tail&&zhi[u]*i<=n*2;u++)use[zhi[u]*i]=true;
	}
	for(int i=1;i<=tail;i++){
		for(int u=1;zhi[i]*u<=2*n;u++){
			int a=zhi[i]*u;
			if(zhi[i]*u<=n){
				while(a%zhi[i]==0){
					f[i]--;
					a/=zhi[i];
				}
			}
			if(zhi[i]*u>n+1){
				while(a%zhi[i]==0){
					f[i]++;
					a/=zhi[i];
				}
			}
		}
	}
	long long ans=1;
	for(int i=1;i<=tail;i++){
		if(f[i]==0)continue;
		ans=ans*sumi(zhi[i],f[i])%mod;
	}
	printf("%d",ans);
	return 0;
}

第二題 乘法

題面如下點選檢視

點選檢視程式碼
乘法 (mul.c/cpp/pas)
1 題目描述
  輸入一個 n ∗ n 的矩陣 A,請求出 A^1+A^2+...+A^k 對 m 取模的結果。
2 輸入格式
  第一行為三個正整數 n, k, m,含義如上所述;
  接下來 n 行,每行輸入 n 個非負整數,用於描述矩陣 A。
3 輸出格式
  輸出 n 行,每行 n 個整數,表示答案矩陣。
4 樣例輸入
  2 2 5
  2 1
  0 3
5 樣例輸出
  1 1
  0 2
6 資料範圍與約定
  對於前 30% 的資料,k<=30;
  對於另外 30% 的資料,n=1;
  對於 100%的資料,n<=30, k<=10^9, m<=10^4
4,輸入矩陣的數在 0~m-1 範圍內。

不得不說矩陣套矩陣然後推快速冪的方法真的是非常的妙啊...


程式碼如下

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int f=1,j=0;char w=getchar();
	while(w>'9'||w<'0'){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(w>='0'&&w<='9'){
		j=(j<<3)+(j<<1)+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=31,M=32;
int n,k,mod;
struct matrix{
	int s[N][N];
	matrix operator *(const matrix &a)const{
		matrix b;
		for(int x=1;x<=n;x++){
			for(int y=1;y<=n;y++){
				long long ansn=0;
				for(int i=1;i<=n;i++)ansn=(ansn+s[x][i]*a.s[i][y])%mod;
				b.s[x][y]=ansn;
			}
		}
		return b;
	}
	matrix operator +(const matrix &a)const{
		matrix b;
		for(int x=1;x<=n;x++){
			for(int y=1;y<=n;y++){
				b.s[x][y]=(s[x][y]+a.s[x][y])%mod;
			}
		}
		return b;
	}
}mid,yuan,kong;
struct node{
	matrix line[2][2];
	node operator *(const node &a)const{
		node b;
		for(int i=0;i<=1;i++){
			for(int u=0;u<=1;u++){
				b.line[i][u]=line[i][0]*a.line[0][u];
				b.line[i][u]=b.line[i][u]+(line[i][1]*a.line[1][u]);
			}
		}
		return b;
	}
}sta;
node sumi(int tim){
	node nown=sta,ansn;
	ansn.line[0][0]=ansn.line[1][1]=yuan;
	ansn.line[1][0]=ansn.line[0][1]=kong;
	while(tim>0){
		if(tim%2==1)ansn=ansn*nown;
		tim/=2;
		nown=nown*nown;
		
	}
	return ansn;
}
signed main(){
	//freopen("mul.in","r",stdin);
	//freopen("mul.out","w",stdout);
	n=read();k=read();mod=read();
	for(int i=1;i<=n;i++)yuan.s[i][i]=1;
	for(int i=1;i<=n;i++)for(int u=1;u<=n;u++)mid.s[i][u]=read();
	sta.line[0][0]=yuan;
	sta.line[0][1]=mid;
	sta.line[1][1]=mid;
	sta.line[1][0]=kong;
	node ansn=sumi(k-1);
	matrix ans;
	ans=ansn.line[0][0]*mid+ansn.line[0][1]*mid;
	for(int i=1;i<=n;i++){
		for(int u=1;u<=n;u++)printf("%d ",ans.s[i][u]);
		printf("\n");
	} 
	return 0;
}

第三題 生物

題面如下(點選檢視)

點選檢視程式碼
生物 (creature.c/cpp/pas)
1 題目描述
  在一個無限長的一維空間中,存在著一個奇特的生物,它的身體上順次有著 n + 1 個刻印,每個刻印可以用一個正整數來表示。已知它最後一個刻印的值為m,而其它 n 個刻印的值均不超過 m,並且兩個刻印的值可以相同。
這個生物每次可以選中它的任意一個刻印,並且按照這個刻印的值 k,選擇向它所在位置的前或後閃爍 k 個單位。我們稱可以使得這個生物能夠通過若干次閃爍,到達一維空間任何一個位置的刻印序列為超刻印序列。
現在刻印序列顯然一共有 m^n 種,為了研究這個生物,請你求出其中超刻印序列的數目。
2 輸入格式
  僅一行兩個整數,分別為 n, m。
3 輸出格式
  輸出一行一個整數,表示超刻印序列的數目對 10^9+7 取模的結果。
4 樣例輸入
  2 4
5 樣例輸出
  12
6 資料範圍與約定
  對於前 20%的資料,保證 n,m <= 5;
 對於 100%的資料,保證 1<=n<=15,1<=m<=10^8。

一切的一切都源於ax+by=gcd(x,y)

程式碼如下

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int f=1,j=0;char w=getchar();
	while(w>'9'||w<'0'){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(w>='0'&&w<='9'){
		j=(j<<3)+(j<<1)+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=16,M=100000001,mod=1000000007;
int n,m,ans=1;
int mi[35],cut,zhi[10001],f[10001],tail,len;
int kkk[10001];
bool use[10001];
int sumi(int sum,int num){
	int ansn=1;
	mi[0]=sum;
	for(int i=1;i<=33;i++)mi[i]=1ll*mi[i-1]*mi[i-1]%mod;
	for(int i=0;i<=33&&num>0;i++){
		if(num%2==1)ansn=(1ll*ansn*mi[i])%mod;
		num/=2;
	}
	return ansn;
}
void rongchi(int aim,int tim,int nown,int front){
	if(tim==aim+1){
		kkk[aim]=(kkk[aim]+sumi(m/nown,n))%mod;
		return ;
	}
	for(int i=front+1;i<=len;i++){
		if(!use[i]){
			use[i]=true;
			rongchi(aim,tim+1,nown*f[i],i);
			use[i]=false;
		}
	}
	return ;
}
signed main(){
	//freopen("creature.in","r",stdin);
	//freopen("creature.out","w",stdout);
	for(int i=2;i<=10000;i++){
		if(!use[i])zhi[++tail]=i;
		for(int u=1;u<=tail;u++)if(zhi[u]*i<=10000)use[zhi[u]*i]=true;
	}
	n=read();m=read();
	int a=m;
	for(int i=1;i<=tail&&zhi[i]<=a;i++){
		if(a%zhi[i]==0)f[++len]=zhi[i];
		while(a%zhi[i]==0){
			a/=zhi[i];
		}
	}
	if(a!=1)f[++len]=a;
	memset(use,0,sizeof(use));
	for(int i=1;i<=len;i++)rongchi(i,1,1,0);
	ans=sumi(m,n);
	long long ansn=0;
	for(int i=1;i<=len;i++){
		if(i%2==1)ansn=(ansn+kkk[i])%mod;
		else ansn=(ansn-kkk[i])%mod;
	}
	printf("%d",((ans-ansn)%mod+mod)%mod);
	return 0;
}