2020牛客寒假算法基础集训营1

链接:https://ac.nowcoder.com/acm/contest/3002#question link
来源:牛客竞赛

A honoka和格点三角形

题目描述

满足以下三个条件的三角形是“好三角形”。
1.三角形的三个顶点均为格点,即横坐标和纵坐标均为整数。
2.三角形的面积为 1。
3.三角形至少有一条边和 x x x轴或 y y y 轴平行。
honoka想知道,在平面中选取一个大小为 n n n* m m m 的矩形格点阵,可以找到多少个不同的“好三角形”?由于答案可能过大,请对1000000007 取模。

输入描述

两个正整数 n n n m m m 2 ≤ n , m ≤ 1 e 9 2\leq n,m \leq1e9 2n,m1e9

思路

运用容斥原理,分别算出与 x x x轴平行的以及与 y y y轴平行的,再减去既与 x x x轴平行的也与 y y y轴平行的。

AC代码

#include<cstdio>
#include<iostream> 
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define mst(s) memset(s,0,sizeof(s))
#define mod 1000000007
ll n, m;
int main(){ 
  scanf("%lld%lld",&n,&m);
  ll ans = ((2*n*m)%mod - (3*n)%mod - (3*m)%mod + 4 + mod)%mod;
  if(ans < 0) ans += mod; 
  ans = (ans*(n+m-2)%mod)%mod; 
  printf("%lld\n",(2*ans)%mod);  }//Accepted!

B kotori和bangdream

链接:link
来源:牛客网

题目描述

有一天,kotori发现了一个和lovelive相似的游戏:bangdream。令她惊讶的是,这个游戏和lovelive居然是同一个公司出的!
kotori经过一段时间的练习后已经变得非常触,每个音符 x x x%的概率perfect,获得 a a a分, ( 100 − x ) (100-x) (100x)% 概率great,获得 b b b分。
已知一首歌有 n n n个音符。kotori想知道,不考虑连击加成的话,一首歌得分的期望是多少?

输入描述

一行 个整数,用空格隔开。分别是 n , x , a , b n,x,a,b n,x,a,b ( 0 ≤ x < = 100 , 1 ≤ n , a , b ≤ 1000 ) (0\leq x<=100,1\leq n,a,b\leq 1000) (0x<=100,1n,a,b1000)

思路

太水了,看代码吧

代码

//
//  main.cpp
//  cpp
//
//  Created by ZhuChenyu on 2020/02/04.
//  Copyright © 2020年 ZhuChenyu. All rights reserved.
//
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MOD 1000007
#define maxn 1000002
#define INF 2147483647
typedef unsigned float_bits;

using namespace std;

//priority_queue <int,vector<int>,greater<int> > que;

int n,x,a,b;
double ans;

int main()
{
    int i,j,t;
    scanf("%d%d%d%d",&n,&x,&a,&b);
    ans=0;
    ans=(double)(x*n*a+(100-x)*n*b);
    ans=ans/100;
    printf("%.2f\n",ans);
 	return 0;
}

C umi和弓道

链接:link
来源:牛客网

题目描述

umi对弓道非常痴迷。
有一天,她在研究一个射箭问题:
在一个无限大的平面中,她站在 ( x x x0, y y y0)这个坐标。
n n n个靶子,第 i i i个靶子的坐标是( x x x i i i, y y y i i i)
umi准备在 x x x轴或 y y y轴上放置一块挡板来挡住弓箭的轨迹,使得她可以射中的靶子数量不超过 k k k个。
她想知道挡板的最短长度是多少?
1:假定弓箭的轨迹是起点为umi坐标、长度无穷大的射线。umi和靶子的体积可以无视。挡板的边缘碰到弓箭轨迹也可视为挡住弓箭。
2:挡板不能弯折,起始和终点必须在同一坐标轴上。

输入描述

第一行两个整数 , x x x0, y y y0代表umi的坐标。
第二行两个正整数 n n n k k k,分别代表靶子的总数量、放置挡板后可射中靶子的最大值。
接下来的 n n n行,每行两个整数 x x x i i i y y y i i i。代表每个靶子的坐标。
保证没有任何一个点在坐标轴上(无论umi还是靶子),保证没有任何两点重合。

输出描述

若无论如何无法保证可以射中的靶子数量不超过 k k k个,则输出 − 1 -1 1
否则输出挡板的最小长度。如果你和正确答案的误差不超 1 0 − 6 10^{-6} 106,则视为答案正确。

思路

将( x x x0, y y y0)与每个( x x x i i i, y y y i i i)连接,求出该线段与两坐标轴的交点坐标。 x x x y y y轴上交点坐标分别排序,随后线性寻找相差 n − k n-k nk个的坐标之差,求出最小值。

代码

//
//  main.cpp
//  cpp
//
//  Created by ZhuChenyu on 2020/02/04.
//  Copyright © 2020年 ZhuChenyu. All rights reserved.
//
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MOD 1000007
#define maxn 100020
#define INF 2147483647
typedef unsigned float_bits;

using namespace std;

//priority_queue <int,vector<int>,greater<int> > que;


int n,k;
long long x0,y01;
long long x,y;
int numx=0,numy=0,numlx=0,numly=0;
double locx[maxn]={0},locy[maxn]={0};
double ansx,ansy;

int main()
{
	int i,j;
	scanf("%lld%lld",&x0,&y01);
    scanf("%d%d",&n,&k);
    
    for (i=1;i<=n;i++)
    {
    	scanf("%lld%lld",&x,&y);
    	if (x*x0>0)
    	{
    		numx++;
    	}
    	else
    	{
    		numly++;
    		locy[numly]=((((double)(y-y01))/((double)(x-x0)))*(double)abs(x0));
    		if (locy[numly]<0) locy[numly]=-locy[numly];
    		if (y>y01) locy[numly]=locy[numly]+(double)y01;
    		else locy[numly]=-locy[numly]+(double)y01;
    	}
    	if (y*y01>0)
    	{
    		numy++;
    	}
    	else
    	{
    		numlx++;
    		locx[numlx]=((((double)(x-x0))/((double)(y-y01)))*(double)abs(y01));
    		if (locx[numlx]<0) locx[numlx]=-locx[numlx];
    		if (x>x0) locx[numlx]=locx[numlx]+(double)x0;
    		else locx[numlx]=-locx[numlx]+(double)x0;
    	}
    }
    if (n-k<=0) 
    {
    	printf("0\n");
    	return 0;
    }

    sort(locx+1,locx+1+numlx);
    sort(locy+1,locy+1+numly);

    /*for (i=1;i<=numlx;i++)
    	cout<<locx[i]<<endl;

   	cout<<endl;
   	for (i=1;i<=numly;i++)
    	cout<<locy[i]<<endl;*/

    if (numx>k)
    {
    	ansy=-1;
    }
    else
    {
    	ansy=locy[numly]-locy[1];
   		for (i=1;i<=numly-(n-k)+1;i++)
   		{
   			ansy=min(ansy,locy[i+n-k-1]-locy[i]);
   		}
    }

    if (numy>k)
    {
    	ansx=-1;
    }
    else
    {
    	ansx=locx[numlx]-locx[1];
    	for (i=1;i<=numlx-(n-k)+1;i++)
    	{
    		ansx=min(ansx,locx[i+n-k-1]-locx[i]);
    	}
    }

    if (ansx<0&&ansy<0)
    {
    	printf("-1\n");
    }
    else
    {
    	if (ansx<0)
    	{
    		printf("%.8f\n",ansy);
    		return 0;
    	}
    	if (ansy<0)
    	{
    		printf("%.8f\n",ansx);
    		return 0;
    	}
    	printf("%.8f\n",min(ansx,ansy));
    }
    //printf("%.8f %.8f\n",ansx,ansy);

 	return 0;
}

备注

此题看起来挺烦的,尤其是涉及到浮点数的计算。这题竟然是本场比赛过的最少的几道之一,看来大家都不屑于做这种苦力活太懒了。其实还是很简便的。

D hanayo和米饭

链接:link
来源:牛客网

题目描述

hanayo很喜欢吃米饭。
有一天,她拿出了 n n n个碗,第一个碗装了 1 1 1粒米饭,第二个碗装了 2 2 2粒米饭,以此类推,第 n n n个碗装了 n n n粒米饭。
然而,爱搞恶作剧的rin把所有的碗的顺序打乱,并拿走了一个碗。hanayo想知道,rin拿走的碗里有多少粒米饭?

思路

简单的读入桶排序?

代码

//
//  main.cpp
//  cpp
//
//  Created by ZhuChenyu on 2019/11/08.
//  Copyright © 2019年 ZhuChenyu. All rights reserved.
//
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MOD 1000007
#define maxn 1000002
#define INF 2147483647
typedef unsigned float_bits;

using namespace std;

//priority_queue <int,vector<int>,greater<int> > que;

int n,b;
int a[100010]={0};
int ans;

int main()
{
	int i,j;
    scanf("%d",&n);
    for (i=1;i<n;i++)
    {
    	scanf("%d",&b);
    	a[b]=1;
    }
    for (i=1;i<=n;i++)
    {
    	if (a[i]==0)
    	{
    		printf("%d\n",i);
    		break;
    	}
    }
 	return 0;
}

E rin和快速迭代

题目描述

f ( x ) f(x) f(x) x x x 的因子个数,将 f f f迭代下去,rin猜想任意正整数最终都会变成 2 2 2
她希望你帮她验证一下。她会给你一个正整数 n n n,让你输出它在迭代过程中,第一次迭代成 2 2 2的迭代次数。

输入描述

一个正整数 n n n ( 3 ≤ n ≤ 1 e 12 ) (3\leq n\leq1e12) (3n1e12)

思路

猜想迭代次数不会很大,直接暴力求解 f ( n ) f(n) f(n),记录到 2 2 2的迭代次数。具体求解方法为进行质因数分解 n n n= p 1 p1 p1^ a 1 a1 a1 * p 2 p2 p2^ a 2 a2 a2 * … * p m pm pm^ a m am am, 则 f ( n ) f(n) f(n) = ( a 1 a1 a1+ 1 1 1) *( a 2 a2 a2+ 1 1 1) * … *( a m am am+ 1 1 1)。(质因数分解的时间复杂度是根号 n n n

AC代码

#include<cstdio>
#include<iostream> 
#include<algorithm>
#include<cstring>
using namespace std;
#define ll unsigned long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define mst(s) memset(s,0,sizeof(s))
ll n, x;
int num[maxn];
int m, ans = 0;
void get(){
    mst(num);
    m = 0;    
    x = n;    
    for(ll i = 2;i * i <= x;i++){        
    if(n % i == 0){            
    m++;            
    while(n%i == 0){                
    n /= i;                
    num[m]++;            
    }        
    }    
    }    
    if(n != 1){        
    m++;        
    num[m] = 1;        
    n = 1;    
    }   
    rep(i,1,m) n *= (num[i]+1);
    } 
    int main(){   
    scanf("%lld",&n);   
    while(n != 2){    
    get();    
    ans++;    
    }   
    printf("%d",ans);   
    }

F maki 和 tree

题目描述

给定一棵树,节点分黑色和白色,问总共有多少对点对,使得这对点之间的最短路径上有且仅有一个黑色节点。
< p , q > <p,q> <p,q> < q , p > <q,p> <q,p> 的取法视为同一种。

输入描述

第一行一个正整数 n n n 。代表顶点数量。( 1 ≤ n ≤ 100000 1\leq n \leq 100000 1n100000)
第二行是一个仅由字符 ′ B ′ 'B' B ′ W ′ 'W' W组成的字符串。第 i i i 个字符是 B B B代表第 i i i 个点是黑色, W W W代表第 i i i 个点是白色。
接下来的 n − 1 n-1 n1 行,每行两个正整数 x x x y y y ,代表 x x x 点和 y y y 点有一条边相连

思路

树上的并查集,合并每一对相邻的白点,枚举每一个黑点,遍历与该黑点相邻的白点块,计入总数,该黑点对答案的贡献就是每块白点块的个数乘以之前的总数再加上它本身(选取黑点)

AC代码

#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
#define maxn 100005
#define ll long long
using namespace std;
char str[maxn];
vector<int>wp[maxn];
int f[maxn],num[maxn];
int find_f(int x){
	if(f[x]==x)return x;
	return f[x]=find_f(f[x]);
}
int n,a,b;
ll ans;
int main(){
	scanf("%d",&n);
	scanf("%s",str+1);
	for(int i=1;i<=n;i++){
		num[i]=1;
		f[i]=i;
	}
	for(int i=1;i<=n-1;i++){
		scanf("%d%d",&a,&b);
		if(str[a]=='W'&&str[b]=='W'){
			int fa=find_f(a),fb=find_f(b);
			num[fa]+=num[fb];
			f[fb]=fa;
		}
		else if(str[a]=='B'&&str[b]=='W'){
			wp[a].push_back(b);
		}
		else if(str[a]=='W'&&str[b]=='B'){
			wp[b].push_back(a);
		}
	}
	for(int i=1;i<=n;i++){
		if(str[i]=='W')continue;
		int now=0;
		for(int j=0;j<wp[i].size();j++){
			int fj=find_f(wp[i][j]);
			ans+=(ll)now*num[fj]+num[fj];
			now+=num[fj];
		}
	}
	printf("%lld",ans);
	return 0;
} 

G eli和字符串

链接:link
来源:牛客网

题目描述

eli拿到了一个仅由小写字母组成的字符串。
她想截取一段连续子串,这个子串包含至少 k k k个相同的某个字母。
她想知道,子串的长度最小值是多少?
注:所谓连续子串,指字符串删除头部和尾部的部分字符(也可以不删除)剩下的字符串。例如:对于字符串“ a r c a e a arcaea arcaea”而言,“ a r c arc arc”、“ r c a e rcae rcae”都是其子串。而“ c a r car car”、“ a a aa aa”则不是它的子串。

输入描述

第一行输入两个正整数 n n n k k k.( 1 ≤ k ≤ n ≤ 200000 ) 1\leq k \leq n \leq 200000) 1kn200000)
输入仅有一行,为一个长度为 n n n的、仅由小写字母组成的字符串。

输出描述

如果无论怎么取都无法满足条件,输出 − 1 -1 1
否则输出一个正整数,为满足条件的子串长度最小值。

思路

分26个字母讨论。

代码

//
//  main.cpp
//  cpp
//
//  Created by ZhuChenyu on 2019/11/08.
//  Copyright © 2019年 ZhuChenyu. All rights reserved.
//
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MOD 1000007
#define maxn 200020
#define INF 2147483647
typedef unsigned float_bits;

using namespace std;

//priority_queue <int,vector<int>,greater<int> > que;

int n,k;
char s[maxn];
int loc[30][maxn]={0};
int num[30]={0};
int ans;

int main()
{
	int i,j;
    scanf("%d%d",&n,&k);
    scanf("%s",s);

    for (i=0;i<strlen(s);i++)
    {
    	num[s[i]-'a']++;
    	loc[s[i]-'a'][num[s[i]-'a']]=i;
    }

    ans=n+10;
    for (i='a'-'a';i<='z'-'a';i++)
    {
    	if (num[i]<k) continue;
    	for (j=1;j<=num[i]-k+1;j++)
    	{
    		ans=min(ans,loc[i][j+k-1]-loc[i][j]+1);
    	}
    }

    if (ans==n+10)
    {
    	printf("-1\n");
    }
    else
    {
    	printf("%d\n",ans);
    }

 	return 0;
}

H nozomi 和字符串

题目描述

给一个"0,1"串,进行不多于k次的操作,每次把串中的0变成1或者把1变成0,在最后的串中找到一条全1或者全0子串,求这个子串的最大长度。

输入描述

第一行输入两个正整数 n n n k k k ( 1 ≤ k ≤ n ≤ 200000 1\leq k \leq n \leq 200000 1kn200000)
输入仅有一行,为一个长度为 n n n 的、仅由字符 0 和 1 组成的字符串。

思路

由"0,1"可以很容易想到前缀和, f [ r ] − f [ l ] f[r]-f[l] f[r]f[l]就是 l l l r r r区间内1的个数,也就得到了0的个数。
枚举 l l l r r r,1的个数小于 k k k的或者0的个数小于 k k k l l l r r r满足条件,求所有这些 l l l r r r中差值的最大值。枚举时间复杂度 n 2 n^2 n2
考虑到给定 l l l 遍历 r r r ,区间内1的个数是单调的,所以可以采用二分,时间复杂度 n ∗ log ⁡ 2 n n* \log_2n nlog2n

AC代码

#include<stdio.h>
#include<algorithm>
#define maxn 200005
using namespace std;
int n,k;
char str[maxn];
int f[maxn];
int ans;
int main(){
    scanf("%d%d",&n,&k);
    scanf("%s",str);
    for(int i=0;i<n;i++){
        f[i+1]=f[i]+str[i]-'0';
    }
//  printf("1:\n");
    for(int i=0;i<n;i++){
        int l=i+1,r=n,mid,res;
        while(l<r){
            mid=(l+r)/2;
            if(f[mid]-f[i]<=k)l=mid+1,res=mid;
            else r=mid-1;
        }
        if(f[l]-f[i]<=k)res=l;
        ans=max(ans,res-i);
//      printf("%d %d %d\n",i,res,ans);
    }
//  printf("0:\n");
    for(int i=0;i<n;i++){
        int l=i+1,r=n,mid,res;
        while(l<r){
            mid=(l+r)/2;
            if(mid-i-(f[mid]-f[i])<=k)l=mid+1,res=mid;
            else r=mid-1;
        }
        if(l-i-(f[l]-f[i])<=k)res=l;
        ans=max(ans,res-i);
//      printf("%d %d %d\n",i,res,ans);
    }
    printf("%d",ans);
}
//Accepted!

I nico和niconiconi

题目描述

nico平时最喜欢说的口头禅是niconiconi~。
有一天nico在逛著名弹幕网站"niconico"的时候惊异的发现,n站上居然有很多她的鬼畜视频。其中有一个名为《让nico为你洗脑》的视频吸引了她的注意。
她点进去一看,就被洗脑了:“niconicoh0niconico*^vvniconicoG(vniconiconiconiconiconicoG(vniconico…”
弹幕中刚开始有很多“nico1 nico2”等计数菌,但到后面基本上都是“计数菌阵亡”的弹幕了。
nico也想当一回计数菌。她认为:“nico” 计 a a a 分,“niconi” 计 b b b 分,“niconiconi” 计 c c c 分。
她拿到了一个长度为 n n n 的字符串,请帮她算出最大计数分数。
注:已被计数过的字符不能重复计数!如"niconico"要么当作"nico"+“nico"计 2 a 2a 2a分,要么当作"niconi”+"co"计 b b b 分。

输入描述

第一行四个正整数 n n n, a a a, b b b, c c c ( 1 ≤ n ≤ 300000 , 1 ≤ a , b , c ≤ 1 e 9 ) (1 \leq n \leq 300000, 1 \leq a,b,c\leq1e9) (1n300000,1a,b,c1e9)
第二行是一个长度为 n n n的字符串

思路

基础dp题,用 f ( n ) f(n) f(n)表示前 n n n个字符构成的字符串的最大计数分数,那么 f ( n ) f(n) f(n)的取值只有四种可能:
当第 n n n个字符与前面字符无法形成加分子字符串时为 f ( n − 1 ) f(n-1) f(n1)
当第 n n n个字符与前面字符能形成加 a a a分的子字符串时为 f ( n − 1 ) f(n-1) f(n1) f ( n − 4 ) f(n-4) f(n4)+ a a a的最大值
当第 n n n个字符与前面字符能形成加 b b b分的子字符串时为 f ( n − 1 ) f(n-1) f(n1) f ( n − 6 ) f(n-6) f(n6)+ b b b的最大值
当第 n n n个字符与前面字符能形成加 c c c分的子字符串时为 f ( n − 1 ) f(n-1) f(n1) f ( n − 10 ) f(n-10) f(n10)+ c c c的最大值

AC代码

#include<cstdio>
#include<iostream> 
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
int n;
ll a, b, c;
char s[maxm];
ll f[maxm];
int main(){
scanf("%d%lld%lld%lld",&n,&a,&b,&c);
scanf("%s",s+1);
rep(i,1,n){    
if(i >= 4 && s[i] == 'o' && s[i-1] == 'c' && s[i-2] == 'i' && s[i-3] == 'n') f[i] = max(f[i],f[i-4] + a);    
if(i >= 6 && s[i] == 'i' && s[i-1] == 'n' && s[i-2] == 'o' && s[i-3] == 'c' && s[i-4] == 'i' && s[i-5] == 'n') f[i] = max(f[i],f[i-6]+b);    
if(i >= 10 && s[i] == 'i' && s[i-1] == 'n' && s[i-2] == 'o' && s[i-3] == 'c' && s[i-4] == 'i' && s[i-5] == 'n' && s[i-6] == 'o' && s[i-7] == 'c' && s[i-8] == 'i' && s[i-9] == 'n') f[i] = max(f[i],f[i-10]+c);    
f[i] = max(f[i],f[i-1]);
}
printf("%lld\n",f[n]);     
}//Accepted!

J u’s的影响力

题目描述

设第 i i i 天的影响力为 f ( i ) f(i) f(i) ,那么 f ( 1 ) f(1) f(1) = x x x f ( 2 ) f(2) f(2) = y y y,对于 i > 2 i > 2 i>2 f ( i ) = f ( i − 1 ) ∗ f ( i − 2 ) ∗ a b f(i) = f(i-1) * f(i-2) *a ^b f(i)=f(i1)f(i2)ab
她们想知道第 n n n天影响力是多少?
由于这个数可能非常大,只需要输出其对 1000000007 1000000007 1000000007 取模的值就可以了。

输入描述

一行五个正整数: n , x , y , a , b ( 1 ≤ n , x , y , a , b ≤ 1 e 12 ) n,x,y,a,b (1 \leq n,x,y,a,b \leq 1e12) n,x,y,a,b(1n,x,y,a,b1e12)

思路

观察前几项就会发现 x x x y y y的幂次是斐波拉契数列的项,我们用矩阵快速幂求解,同时由于模是个质数,我们对指数可以进行模模数减一的操作。而且我们发现最后一项 a b a^b ab b b b的系数是数列 A n = A ( n − 1 ) + A ( n − 2 ) + 1 An=A(n-1)+A(n-2)+1 An=A(n1)+A(n2)+1的项,我们进行线性变换以后运用同样的方法即可计算出值了。

AC代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll __int128
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define mst(s) memset(s,0,sizeof(s))
#define ls(x) x<<1
#define rs(x) x<<1|1
#define lb(x) x&-x
#define pii pair<int,int>
#define pli pair<ll,int>
#define pll pair<ll,ll>
#define pi acos(-1)
#define F first
#define S second
#define cuts printf("\n--------------\n");
#define maxn 100005
#define maxm 400005
#define mod 1000000007
ll n, f[10], p, q, ans = 1;
struct mat{
    ll m[2][2];
};
  
struct mat mul(struct mat a,struct mat b,ll y){
    struct mat res;
    res.m[0][0] = (a.m[0][0]*b.m[0][0]%y + a.m[0][1]*b.m[1][0]%y)%y;
    res.m[0][1] = (a.m[0][0]*b.m[0][1]%y + a.m[0][1]*b.m[1][1]%y)%y;
    res.m[1][0] = (a.m[1][0]*b.m[0][0]%y + a.m[1][1]*b.m[1][0]%y)%y;
    res.m[1][1] = (a.m[1][0]*b.m[0][1]%y + a.m[1][1]*b.m[1][1]%y)%y;
    return res;
}
  
struct mat matksm(struct mat a,ll x,ll y){
    struct mat res;
    res.m[0][0] = 1,res.m[0][1] = 0;
    res.m[1][0] = 0, res.m[1][1] = 1;
//  printf("%lld",x);
    while(x){
        if(x&1) res = mul(res,a,y);
        x >>= 1;
        a = mul(a,a,y);
    //  printf("%lld\n",x);
    }
    return res;
}
  
ll ksm(ll a,ll x,ll y){
    ll res = 1;
    while(x){
        if(x&1) res = res*a%y;
        x >>= 1;
        a = a * a %y;
          
    }
    return res;
}
  
int main(){
    scanf("%lld%lld%lld%lld%lld",&n,&f[1],&f[2],&p,&q);
    struct mat A;
    A.m[0][0] = 1, A.m[0][1] = 1;
    A.m[1][0] = 1, A.m[1][1] = 0;
    if(n == 1) printf("%lld",f[1]%mod);
    else if(n == 2) printf("%lld",f[2]%mod);
    else{
    struct mat A1 = matksm(A,n-3,mod-1);
    struct mat A2 = matksm(A,n-2,mod-1);
    p = ksm(p,q,mod);
    ll x1 = (A1.m[0][1] + A1.m[1][1])%(mod-1);
    ll y1 = (A2.m[0][1] + A2.m[1][1])%(mod-1);
    ll b1 = (A1.m[0][1]*3%(mod-1) + A1.m[1][1]*2%(mod-1))%(mod-1);
    b1 = (b1 - 1 + mod - 1)%(mod-1);
   // printf("%lld %lld\n", ksm(f[1],x1),ksm(f[2],y1));
    ans = ksm(f[1],x1,mod)*ksm(f[2],y1,mod)%mod;
    ans = ans*ksm(p,b1,mod)%mod;
    printf("%lld\n",ans);
    }
  
     
}
//Accepted!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值