比赛链接:https://ac.nowcoder.com/acm/contest/3002
题目描述
honoka最近在研究三角形计数问题。
她认为,满足以下三个条件的三角形是“好三角形”。
1.三角形的三个顶点均为格点,即横坐标和纵坐标均为整数。
2.三角形的面积为。
3.三角形至少有一条边和 x x x 轴或 y y y 轴平行。
honoka想知道,在平面中选取一个大小为 n ∗ m n*m n∗m 的矩形格点阵,可以找到多少个不同的“好三角形”?
由于答案可能过大,请对 1000000007 1000000007 1000000007 取模。
输入描述:
两个正整数和( 2 ≤ n , m ≤ 1 0 9 2 \le n,m \le 10^9 2≤n,m≤109 )
输出描述:
面积为1的格点三角形的数量,对 1 e 9 + 7 1e9+7 1e9+7 取模的结果。
解题思路:
分为底为1高为2,底为2高为1,每种情况又可分成底平行于 x x x 轴或者底平行于 y y y 轴。
a n s = ( m − 2 ) ∗ m ∗ ( n − 1 ) ∗ 2 + ( n − 2 ) ∗ n ∗ ( m − 1 ) ∗ 2 + ( n − 1 ) ∗ ( m − 2 ) ∗ ( n − 2 ) ∗ 2 + ( m − 1 ) ∗ ( n − 2 ) ∗ ( m − 2 ) ∗ 2 ans = (m-2)*m*(n-1)*2 + (n-2)*n*(m-1)*2 + (n-1)*(m-2)*(n-2)*2 + (m-1)*(n-2)*(m-2)*2 ans=(m−2)∗m∗(n−1)∗2+(n−2)∗n∗(m−1)∗2+(n−1)∗(m−2)∗(n−2)∗2+(m−1)∗(n−2)∗(m−2)∗2 ,每一步取模。注意不能重复。
Code:
#include
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
typedef long long ll;
const int MOD = 1000000007;
ll M(ll x, ll y) { return ((x % MOD) * (y % MOD)) % MOD; }
int main()
{
IO;
ll n, m;
cin >> n >> m;
ll ans = 0;
ans = (M(M(m - 2, m), M(2, n - 1)) + M(M(n - 2, n), M(2, m - 1)) + M(M(n - 1, m - 2), M(n - 2, 2)) + M(M(m - 1, n - 2), M(m - 2, 2))) % MOD;
cout << ans << endl;
return 0;
}
/*
示例1
2 3
6
示例2
100 100
7683984
*/
题目描述
有一天,kotori发现了一个和lovelive相似的游戏:bangdream。令她惊讶的是,这个游戏和lovelive居然是同一个公司出的!
kotori经过一段时间的练习后已经变得非常触,每个音符 x % x\% x% 的概率perfect,获得 a a a 分, ( 100 − x ) % (100−x)\% (100−x)% 概率great,获得 b b b 分。
已知一首歌有 n n n 个音符。kotori想知道,不考虑连击加成的话,一首歌得分的期望是多少?
输入描述:
一行 4 4 4 个整数,用空格隔开。分别是 n , x , a , b n,x,a,b n,x,a,b 。
( 0 ≤ x ≤ 100 , 1 ≤ n , a , b ≤ 1000 0 \le x \le 100,1 \le n,a,b \le 1000 0≤x≤100,1≤n,a,b≤1000 )
输出描述:
一首歌得分的期望,保留两位小数。
输入
100 50 500 400
输出
45000.00
说明
如果全perfect是50000分,全great是40000分。由于它们的概率都是50%,即perfect和great五五开,所以期望是45000分。
解题思路:
这是一个简单的求数学期望的问题。
Code:
#include
int main() {
int n, x, a, b;
scanf("%d%d%d%d", &n, &x, &a, &b);
printf("%.2f\n", (a * n * x + b * n * (100 - x)) / 100.0);
return 0;
}
题目描述
hanayo很喜欢吃米饭。
有一天,她拿出了 n n n 个碗,第一个碗装了 1 1 1 粒米饭,第二个碗装了 2 2 2 粒米饭,以此类推,第 n n n 个碗装了 n n n 粒米饭。
然而,爱搞恶作剧的rin把所有的碗的顺序打乱,并拿走了一个碗。hanayo想知道,rin拿走的碗里有多少粒米饭?
输入描述:
第一行输入一个正整数 n n n 。代表原始的总碗数。
第二行输入 n n n 个正整数 a i a_i ai ,代表目前每碗里米饭数量。
保证输入合法。
( 2 ≤ n ≤ 100000 , 1 ≤ a i ≤ n 2 \le n \le 100000,1 \le a_i \le n 2≤n≤100000,1≤ai≤n)
输出描述:
输出一个正整数,代表rin拿走的碗里米饭数量。
解题思路:
用数组a标记,再遍历一遍数组a找未被标记的输出下标。
Code:
#include
#include
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
int n;
bool a[100002];
int main() {
IO;
cin >> n;
int x;
memset(a, false, sizeof(a));
for (int i = 1; i <= n; i++) {
cin >> x;
a[x] = true;
}
for (int i = 1; i <= n; i++) {
if (!a[i]) {
cout << i << endl;
return 0;
}
}
return 0;
}
/*
示例
5
2 5 1 3
4
*/
题目描述
rin最近喜欢上了数论。
然而数论实在太复杂了,她只能研究一些简单的问题。
这天,她在研究正整数因子个数的时候,想到了一个“快速迭代”算法。设 f ( x ) f(x) f(x) 为 x x x 的因子个数,将 f f f 迭代下去,rin猜想任意正整数最终都会变成 2 2 2 。
例如: f ( 12 ) = 6 , f ( 6 ) = 4 , f ( 4 ) = 3 , f ( 3 ) = 2 f(12)=6,f(6)=4,f(4)=3,f(3)=2 f(12)=6,f(6)=4,f(4)=3,f(3)=2 。
她希望你帮她验证一下。她会给你一个正整数 ,让你输出它在迭代过程中,第一次迭代成 2 2 2 的迭代次数。
输入描述:
一个正整数 n n n( 3 ≤ n ≤ 1 0 12 3 \le n \le 10^{12} 3≤n≤1012)
输出描述:
一个正整数,为 n n n 迭代至 2 2 2 的次数。
解题思路:
暴力求解。
Code:
#include
#include
#include
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
typedef long long ll;
ll get(ll x) {
ll sum = 0, sq = sqrt(x); //开方,降低复杂度
for (ll i = 1; i <= sq; i++) {
if (x % i == 0) {
sum += 2;
}
}
if (sq * sq == x) {
sum--;
}
return sum;
}
int main() {
IO;
ll n, ans = 0;
cin >> n;
for (;;) {
ans++;
if ((n = get(n)) == 2) break;
}
cout << ans << endl;
return 0;
}
/*
示例1
12
4
*/
题目描述
有一天,maki拿到了一颗树。所谓树,即没有自环、重边和回路的无向连通图。
这个树有 n n n 个顶点, n − 1 n-1 n−1 条边。每个顶点被染成了白色或者黑色。
maki想知道,取两个不同的点,它们的简单路径上有且仅有一个黑色点的取法有多少?
注:
①树上两点简单路径指连接两点的最短路。
② < p , q >
<q,p> 的取法视为同一种。
输入描述:
第一行一个正整数 n n n 。代表顶点数量。( 1 ≤ n ≤ 100000 1 \le n \le 100000 1≤n≤100000)
第二行是一个仅由字符 ‘B’ 和 ‘W’ 组成的字符串。第 i i i 个字符是 B 代表第 i i i 个点是黑色, W 代表第 i i i 个点是白色。
接下来的 n − 1 n-1 n−1 行,每行两个正整数 x x x , y y y ,代表 x x x 点和 y y y 点有一条边相连 ( 1 ≤ x , y ≤ n 1 \le x,y \le n 1≤x,y≤n)
输出描述:
一个正整数,表示只经过一个黑色点的路径数量。
样例输入
3
WBW
1 2
2 3
样例输出
3
说明
解题思路:
并查集预处理白色连通块,统计每个白色连通块内点的数量。
一条路径中只经过一个黑点,我们可以先确定黑点,再确定路径。
经过一个黑点的路径有两种:两个端点都是白点;其中一个端点是黑点。
树中两个点之间的路径只有一条,只要两个端点不完全相同,那么这条路径就不相同。所以我们可以选黑点相邻的白色连通块中的任意一个点(即白色连通块的大小)。
Code:
#include
using namespace std;
typedef long long ll;
const int N = 100002;
int n;
char str[N];
vector<int> e[N];
int fa[N], cnt[N];
int findd(int x)
{
if (fa[x] == x)
return x;
else
{
fa[x] = findd(fa[x]);
return fa[x];
}
}
void mergee(int x, int y)
{
int fx = findd(x), fy = findd(y);
if (fx != fy)
{
fa[fy] = fx;
cnt[fx] += cnt[fy];
}
}
int main()
{
scanf("%d", &n);
scanf("%s", str + 1);
int u, v;
for (int i = 1; i <= n; i++)
{
fa[i] = i;
cnt[i] = 1;
}
for (int i = 0; i < n - 1; i++)
{
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
if (str[u] == 'W' && str[v] == 'W')
mergee(u, v);
}
ll ans = 0;
for (int i = 1; i <= n; i++)
{
if (str[i] == 'B')
{
ll sum = 0;
for (int j = 0; j < e[i].size(); j++)
{
v = e[i][j];
if (str[v] == 'W')
{
int t = findd(v);
ans += cnt[t] + sum * cnt[t];
sum += cnt[t];
}
}
}
}
printf("%lld\n", ans);
return 0;
}
题目描述
eli拿到了一个仅由小写字母组成的字符串。
她想截取一段连续子串,这个子串包含至少 k k k 个相同的某个字母。
她想知道,子串的长度最小值是多少?
注:所谓连续子串,指字符串删除头部和尾部的部分字符(也可以不删除)剩下的字符串。例如:对于字符串“arcaea”而言,“arc”、“rcae”都是其子串。而“car”、“aa”则不是它的子串。
输入描述:
第一行输入两个正整数 n n n 和 k k k( 1 ≤ k ≤ n ≤ 200000 1 \le k \le n \le 200000 1≤k≤n≤200000)
输入仅有一行,为一个长度为 n n n 的、仅由小写字母组成的字符串。
输出描述:
如果无论怎么取都无法满足条件,输出 − 1 -1 −1 。
否则输出一个正整数,为满足条件的子串长度最小值。
解题思路:
分别找26个字母,每次先记录下字母ch
的所有位置,然后再用记录下的位置更新最小值。
Code:
#include
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int n, k;
string s;
int len, book[200002];
int main() {
IO;
cin >> n >> k;
cin >> s;
len = s.length();
int ans = INF;
for (int i = 0; i < 26; i++) {
char ch = 'a' + i;
int cnt = 0;
memset(book, 0, sizeof(book)); //清0
for (int j = 0; j < len; j++) { //记录ch的所有位置
if (s[j] == ch) {
book[cnt++] = j;
}
}
if (cnt < k) continue; //如果ch不够k个
for (int j = 0; j <= cnt - k; j++) { //连续的k个为一个子串,更新最小值
ans = min(ans, book[j + k - 1] - book[j] + 1);
}
}
if (ans < INF) cout << ans << endl;
else cout << -1 << endl;
return 0;
}
/*
示例1
5 2
abeba
3
说明:选择“beb”子串,长度为3,其中包含相同的两个'b'
*/
题目描述
nozomi看到eli在字符串的“花园”里迷路了,决定也去研究字符串问题。
她想到了这样一个问题:
对于一个“01”串而言,每次操作可以把 0 字符改为 1 字符,或者把 1 字符改为 0 字符。所谓“01”串,即只含字符 0 和字符 1 的字符串。
nozomi有最多 k k k 次操作的机会。她想在操作之后找出一个尽可能长的连续子串,这个子串上的所有字符都相同。
nozomi想问问聪明的你,这个子串的长度最大值是多少?
注: k k k 次操作机会可以不全部用完。
如果想知道连续子串的说明,可以去问问eli,nozomi不想再讲一遍。
输入描述:
第一行输入两个正整数 n n n 和 k k k( 1 ≤ k ≤ n ≤ 200000 1 \le k \le n \le 200000 1≤k≤n≤200000)
输入仅有一行,为一个长度为 n n n 的、仅由字符 0 0 0 和 1 1 1 组成的字符串。
输出描述:
一个正整数,为满足条件的子串长度最大值。
解题思路:
题目要求最多改 k k k 次,这 k k k 次肯定是全都改 0 0 0 或者全都改 1 1 1 ,答案就是由某次更改连续 k k k 个 0 0 0 或 1 1 1 得来的。所以只要求出所有的连续 k k k 个 0 0 0 和连续 k k k 个 1 1 1 区间的长度,取最大值即可。
用两个数组a
、b
分别记录 0 0 0 和 1 1 1 的位置,以 k k k 长度为间隔分别遍历数组a
、b
。以遍历a
数组为例(修改 0 0 0), a n s = m a x ( a n s , a [ j + 1 ] − a [ i − 1 ] − 1 ) , 其 中 j − i + 1 = k ans = max(ans, a[j + 1] - a[i - 1] - 1),其中j-i+1=k ans=max(ans,a[j+1]−a[i−1]−1),其中j−i+1=k,意思就是修改第 i i i 个 0 0 0 到第 j j j 个 0 0 0 ,一共修改 k k k 个 0 0 0,修改后连续相同1的长度就是第 i − 1 i-1 i−1 个 0 0 0 到第 j + 1 j+1 j+1 个 0 0 0 之间的距离。
这里有个小问题,要在开头和结尾加上两个辅助点 − 1 -1 −1 和 n n n 。设想,如果 j j j 是最后一个 0 0 0 ,那么他就没有 j + 1 j+1 j+1 个点来求修改后的距离,此时修改后的距离是到字符串结尾的距离,所以要在数组最后加上 n n n ,同理开头一样。
Code:
#include
#include
#include
#include
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
const int INF = 0x3f3f3f3f;
int n, k;
string s;
vector<int> a, b;
int ans;
int main() {
IO;
cin >> n >> k >> s;
a.push_back(-1);
b.push_back(-1); //多一个
for (int i = 0; i < n; i++) {
if (s[i] == '0') a.push_back(i);
else b.push_back(i);
}
a.push_back(n);
b.push_back(n); //多两个
if (a.size() - 2 <= k) ans = n;
else { //0大于k个
for (int i = 1, j = k; j < a.size() - 1; i++, j++) {
ans = max(ans, a[j + 1] - a[i - 1] - 1);
}
}
if (b.size() - 2 <= k) ans = n; //前面多两个,减2
else { //1大于k个
for (int i = 1, j = k; j < b.size() - 1; i++, j++) {
ans = max(ans, b[j + 1] - b[i - 1] - 1);
}
}
cout << ans << endl;
return 0;
}
/*
示例
5 1
10101
3
*/
题目描述
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 , a , b , c n,a,b,c n,a,b,c 。( 1 ≤ n ≤ 300000 , 1 ≤ a , b , c ≤ 1 0 9 1 \le n \le 300000,1 \le a,b,c \le 10^9 1≤n≤300000,1≤a,b,c≤109)
第二行是一个长度为 n n n 的字符串。
输出描述:
一个整数,代表最大的计数分数。
解题思路:
动态规划。 d p [ i ] dp[i] dp[i] 代表前 i i i 个字符的计数最大值,状态转移方程见代码。
直接看代码吧,比较好理解。
Code:
#include
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
typedef long long ll;
ll n, a, b, c, f[300002];
string str;
int main()
{
IO;
cin >> n >> a >> b >> c;
cin >> str;
for (int i = 0; i < n; ++i)
{
if (i != 0)
f[i] = f[i - 1];
if (i >= 3 && str.substr(i - 3, 4) == "nico")
f[i] = max(f[i], f[i - 3] + a);
if (i >= 5 && str.substr(i - 5, 6) == "niconi")
f[i] = max(f[i], f[i - 5] + b);
if (i >= 9 && str.substr(i - 9, 10) == "niconiconi")
f[i] = max(f[i], f[i - 9] + c);
}
cout << f[n - 1] << endl;
return 0;
}
/*
输入
19 1 2 5
niconiconiconiconi~
输出
7
*/
题目描述
本题测试样例已经更(jia)新(qiang)。
μ’s在九人齐心协力下,影响力越来越大了!
已知第一天影响力为 x x x ,第二天影响力为 y y y ,从第三天开始,每一天的影响力为前两天影响力的乘积再乘以 a a a 的 b b b 次方。 用数学语言描述是:
设第 i i i 天的影响力为 f ( i ) f(i) f(i) ,那么 f ( 1 ) = x , f ( 2 ) = y f(1)=x,f(2)=y f(1)=x,f(2)=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(i−1)∗f(i−2)∗ab
她们想知道第 n n n 天影响力是多少?
由于这个数可能非常大,只需要输出其对 1000000007 1000000007 1000000007 取模的值就可以了。
输入描述:
一行五个正整数: 。
输出描述:
第 天的影响力对 取模的值。
输入
4 2 3 2 1
输出
72
说明
f ( 1 ) = 2 , f ( 2 ) = 3 , f ( 3 ) = f ( 1 ) ∗ f ( 2 ) ∗ 2 = 12 , f ( 4 ) = f ( 2 ) ∗ f ( 3 ) ∗ 2 = 72 f(1)=2,f(2)=3,f(3)=f(1)*f(2)*2=12,f(4)=f(2)*f(3)*2=72 f(1)=2,f(2)=3,f(3)=f(1)∗f(2)∗2=12,f(4)=f(2)∗f(3)∗2=72
备注:
1000000007 1000000007 1000000007 是素数。
解题思路:
数论,矩阵快速幂。
显然 f ( n ) f(n) f(n) 可以用 x x x , y y y 和 a a a 这三个因子表达出来。
每一项 a a a 的幂次分别是 0 、 0 、 b 、 2 b 、 4 b 、 7 b 、 12 b … … 0、0、b、2b、4b、7b、12b…… 0、0、b、2b、4b、7b、12b…… 从第三项开始每一项为前两项之和加 1 1 1 。
而 x x x 和 y y y 的幂次构成斐波那契数列: x x x 的幂次第一项是 1 1 1 ,第二项是 0 0 0 ; y y y 的幂次第一项是 0 0 0 ,第二项是 1 1 1 。之后每一项均为前两项之和。
根据费马小定理,由于 1 e 9 + 7 1e9+7 1e9+7 是素数,有 a 1 e 9 + 6 ≡ 1 ( m o d 1 e 9 + 7 ) a^{1e9+6 }≡1(mod 1e9+7) a1e9+6 ≡1(mod 1e9+7) 。因此幂的指数对 1 e 9 + 6 1e9+6 1e9+6 取模即可。要注意 a a a 是 1000000007 1000000007 1000000007 的倍数的特殊情况。
可以用矩阵快速幂 O ( l o g n ) O(logn) O(logn) 求出 x 、 y 、 a x、y、a x、y、a 幂次的第 n n n 项。
矩阵快速幂求斐波那契数列的第 n n n 项方法如下:
假设 f ( i ) f(i) f(i) 代表斐波那契数列的第 i i i 项,显然有:
[ 0 1 1 1 ] ∗ [ f ( i ) f ( i + 1 ) ] = [ f ( i + 1 ) f ( i ) + f ( i + 1 ) ] = [ f ( i + 1 ) f ( i + 2 ) ] \begin{bmatrix} 0 & 1\\ 1 & 1 \end{bmatrix} * \begin{bmatrix} f(i)\\ f(i+1) \end{bmatrix} =\begin{bmatrix} f(i+1)\\ f(i)+f(i+1) \end{bmatrix} =\begin{bmatrix} f(i+1)\\ f(i+2) \end{bmatrix} [0111]∗[f(i)f(i+1)]=[f(i+1)f(i)+f(i+1)]=[f(i+1)f(i+2)]
因此
[ 0 1 1 1 ] n ∗ [ f ( 1 ) f ( 2 ) ] = [ f ( n + 1 ) f ( n + 2 ) ] \begin{bmatrix} 0 &1\\ 1 &1 \end{bmatrix}^n * \begin{bmatrix} f(1)\\ f(2) \end{bmatrix} = \begin{bmatrix} f(n+1)\\ f(n+2) \end{bmatrix} [0111]n∗[f(1)f(2)]=[f(n+1)f(n+2)]
而 [ 0 1 1 1 ] n \begin{bmatrix} 0& 1\\ 1&1 \end{bmatrix}^n [0111]n 的值可以用快速幂算出来,这样就可以 O ( l o g n ) O(logn) O(logn) 实现计算斐波那契数列的第 n n n 项了。
假设 g ( i ) g(i) g(i) 代表求 a a a 的幂次的公式 g ( i + 2 ) = g ( i ) + g ( i + 1 ) + 1 g(i+2)=g(i)+g(i+1)+1 g(i+2)=g(i)+g(i+1)+1 ,矩阵的递推式如下:
[ 0 1 0 1 1 1 0 0 1 ] ∗ [ f ( i ) f ( i + 1 ) 1 ] = [ f ( i + 1 ) f ( i ) + f ( i + 1 ) + 1 1 ] = [ f ( i + 1 ) f ( i + 2 ) 1 ] \begin{bmatrix} 0 & 1 & 0\\ 1 & 1 &1\\0 & 0 & 1\end{bmatrix} * \begin{bmatrix} f(i)\\ f(i+1) \\1 \end{bmatrix} =\begin{bmatrix} f(i+1)\\ f(i)+f(i+1)+1\\ 1 \end{bmatrix} =\begin{bmatrix} f(i+1)\\ f(i+2)\\ 1 \end{bmatrix} ⎣⎡010110011⎦⎤∗⎣⎡f(i)f(i+1)1⎦⎤=⎣⎡f(i+1)f(i)+f(i+1)+11⎦⎤=⎣⎡f(i+1)f(i+2)1⎦⎤
Code:
#include
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
typedef long long ll;
struct Mat {
ll a[3][3];
};
Mat Mul(Mat a, Mat b, ll mod) { //矩阵乘法
Mat res;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
res.a[i][j] = 0;
for (int k = 0; k < 3; k++) {
res.a[i][j] += a.a[i][k] * b.a[k][j] % mod;
res.a[i][j] %= mod;
}
}
}
return res;
}
Mat power(Mat a, ll b, ll mod) { //矩阵快速幂a^b%mod
Mat res;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
res.a[i][j] = 0;
}
}
res.a[0][0] = res.a[1][1] = res.a[2][2] = 1;
while (b) {
if (b & 1)
res = Mul(res, a, mod);
b >>= 1;
a = Mul(a, a, mod);
}
return res;
}
ll feb(ll n, ll mod) { //求x、y的幂次
Mat base;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
base.a[i][j] = 0;
}
}
base.a[0][1] = base.a[1][1] = base.a[1][0] = base.a[1][2] = 1;
Mat res = power(base, n - 1, mod);
return (res.a[0][0] + res.a[0][1]) % mod;
}
ll feb2(ll n, ll mod) { //求a的幂次
Mat base;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
base.a[i][j] = 0;
}
}
base.a[0][1] = base.a[1][1] = base.a[1][0] = base.a[1][2] = base.a[2][2] = 1;
Mat res = power(base, n - 1, mod);
return (res.a[0][0] + 2 * res.a[0][1] + res.a[0][2]) % mod;
}
ll power(ll a, ll b, ll mod) { //快速幂a^b%mod
ll res = 1;
while (b) {
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int main() {
int m = 1e9 + 7;
ll n, x, y, a, b;
cin >> n >> x >> y >> a >> b;
if (n == 1) {
cout << x % m << endl;
return 0;
}
if (n == 2) {
cout << y % m << endl;
return 0;
}
if (x % m == 0 || y % m == 0 || a % m == 0) {
cout << 0 << endl;
return 0;
}
x %= m;
y %= m;
//这里要注意a对m取模
a = power(a % m, b, m);
//模m-1是因为费马小定理
cout << power(x, feb(n - 2, m - 1), m) * power(y, feb(n - 1, m - 1), m) % m * power(a % m, feb2(n - 2, m - 1) % (m - 1), m) % m << endl;
return 0;
}
附 牛客的题解含标程
作者 神崎兰子
https://ac.nowcoder.com/discuss/364600?type=101&order=0&pos=2&page=3