2022五一爆零記總結二
阿新 • • 發佈:2022-05-06
五一第三天 ,被關在學校不能出去玩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;
}