A.张老师和菜哭武的游戏
链接:https://ac.nowcoder.com/acm/contest/5477/A
来源:牛客网
天才程序员菜哭武和张老师有一天到一个城市旅游,旅途中菜哭武觉得无聊就想和张老师玩一个游戏。菜哭武有n个石子,每个石子都标有1到n之间到数,且各不相同,一开始他们会随机从这堆石子选一个石子放置到一个集合中,张老师选的数是a,菜哭武选的是b(a和b不相同)。接下来菜哭武和张老师轮流按照如下规则拿走一个石子:当石子x能被拿走时,当且仅当集合存在y和z,满足x等于y+z或者y-z,当x被拿走时,把它放到集合中。谁完成最后一轮操作时,谁获胜。张老师总是先手,于是张老师就好奇当决定好a和b时,他是否总是能获胜,你能帮助一下张老师吗?
输入描述:
第一行一个整数T(1≤T≤500),表示共有T组测试数据。
对于每组测试数据,第一行三个整数n(2≤n≤20000)、a和b(1≤a,b≤n, a≠b)。
输出描述:
若张老师能获胜输出Yes,反之No。
输入
复制16 2 1 2 3 1 3 67 1 2 100 1 2 8 6 8 9 6 8 10 6 8 11 6 8 12 6 8 13 6 8 14 6 8 15 6 8 16 6 8 1314 6 8 1994 1 13 1994 7 12
输出
复制No Yes Yes No No No Yes Yes No No Yes Yes No Yes No No
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(){ int t; cin>>t; for(int i=0;i<t;i++){ int n,a,b; cin>>n>>a>>b; if((n/__gcd(a,b))%2)cout<<"Yes\n"; else cout<<"No\n"; } return 0; }
B。伤害计算
链接:https://ac.nowcoder.com/acm/contest/5477/B
来源:牛客网
勇士菜哭武获得了一把新的武器,武器有特殊的伤害计算方式。武器的伤害计算方式由若干个部分的和组成,用+号连接。每一部分可以是一个整数a,或者是一个公式ndx。其中a表示固定伤害a点;ndx表示掷n个x面骰子,伤害是所有骰子点数的和。总伤害是每一部分伤害的和。
比如2d6+1d70+3,表示掷两个6面骰子和一个70面骰子(不一定实际存在70面骰子,可以理解成1到70当中随机选择一个整数),再加上固定伤害3点。
他正准备挑选一把好武器,需要计算新武器的伤害期望值,想让你帮他计算一下。
输入描述:
输入一个字符串,表示伤害计算公式。字符串长度不超过5000,对于每一个部分,1≤a, n, x≤1000。a,n,x都是整数。
输出描述:
输出一个数,表示伤害的期望值。如果不是整数,小数点后位数保留最少,即最终结果只有可能是整数或者小数点后是.5的形式,如果不是整数,那么保留一位小数。
输出
复制50.5
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll INF = 0x3f3f3f3f; char str[10010]; int parse(char *p){ char *d = strchr(p,'d'); if(d==NULL){ return atoi(p)*2; }else{ *d='\0'; int n = atoi(p); int x = atoi(d+1); return (x+1)*n; } } int main() { cin>>str; int len = strlen(str); char *p = str; ll ans = 0; while(1){ char *ne = strchr(p,'+'); if(ne==NULL){ ans += parse(p); break; }else{ *ne='\0'; ans+=parse(p); p=ne+1; } } cout<<ans/2; if(ans%2)cout<<".5"; cout<<endl; return 0; }
C.张老师的旅行
链接:https://ac.nowcoder.com/acm/contest/5477/C
来源:牛客网
张老师到了一个王国去旅游,王国有n个景点,张老师到达这个城市所在的车站恰好位于第x个景点,这个王国非常特别,恰好所有著名的景点都在分布在直线上,每个景点在坐标pi上(单位:公里),张老师身体非常好,每走一公里花费一分钟。每个景点都有一个打卡点,并且必须在不迟于相应的时间(时间从张老师到达王国开始计算)前到达才能打卡成功并且给以一个打卡标记,集齐所这些标记就能获得一个大礼包。由于张老师非常想要大礼包,并且因为张老师还着急去下一个王国旅游,所以张老师希望用的时间尽量少,你能帮帮张老师吗?
输入描述:
输入的第一行,包含一个整数n(1≤n≤1000)。
第二行包含n个整数pi(1≤pi≤100000),第i个整数pi为第i个景点的坐标(坐标从小到大排列)。
最后一行包含n个整数ti(0≤ti≤10,000,000),ti表示第i个景点最迟到达的时间,时间为0则表示张老师所在车站的位置且只有一个为0。
输出描述:
输出所需的最少时间,若无解输出-1。
输出
复制3
#include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; int dp[1001][1001][2]; struct node{ int t=0,l=0; }a[1001],b[1001],c[1001]; bool cmp(node x,node y){return x.l<y.l;} int main(){ int n;cin>>n; for(int i=1;i<=n;i++)cin>>a[i].l; for(int i=1;i<=n;i++)cin>>a[i].t; sort(a+1,a+1+n,cmp); int k; for(int i=1;i<=n;i++){ if(a[i].t==0)k=i; } memset(dp,INF,sizeof(dp)); int x=0,y=0; dp[0][0][1]=dp[0][0][0]=0; for(int i=k-1;i>0;i--)x++,b[x].l=abs(a[i].l-a[k].l),b[x].t=a[i].t;//求左边点集 for(int i=k+1;i<=n;i++)y++,c[y].l=abs(a[i].l-a[k].l),c[y].t=a[i].t;//求右边点集 for(int i=0;i<=x;i++){ for(int j=0;j<=y;j++){ if(i)dp[i][j][0]=min(dp[i-1][j][0]+b[i].l-b[i-1].l,dp[i-1][j][1]+c[j].l+b[i].l); if(j)dp[i][j][1]=min(dp[i][j-1][1]+c[j].l-c[j-1].l,dp[i][j-1][0]+c[j].l+b[i].l); if(dp[i][j][0]>b[i].t&&dp[i][j][1]>c[j].t){cout<<-1;return 0;} if(dp[i][j][0]>b[i].t)dp[i][j][0]=INF; if(dp[i][j][1]>c[j].t)dp[i][j][1]=INF; } } cout<<min(dp[x][y][0],dp[x][y][1]); }
D。车辆调度
链接:https://ac.nowcoder.com/acm/contest/5477/D
来源:牛客网
张老师设计了一个智能调度系统来控制他的遥控车队,今天,他带着他的车队来到黄渡理工大学的一块空地上测试这个系统。
这块空地可以描述为一个 w * h 大小的长方形,广场上有一些障碍物,几个目标点,当然,还有张老师的车队。
每分钟,调度系统会智能地向其中的一辆遥控车发送以下指令的其中一条:
-
向北走,直到撞到空地的边界、障碍物或其他遥控车;
-
向南走,直到撞到空地的边界、障碍物或其他遥控车;
-
向西走,直到撞到空地的边界、障碍物或其他遥控车;
-
向东走,直到撞到空地的边界、障碍物或其他遥控车;
每条指令都会在一分钟之内完成,也就是说,空地上最多只有一辆遥控车在运动。此外,当遥控车无法向相应的方向移动时,它会停在原地。
你想知道,在第 k 分钟时,有没有可能有任意一辆遥控车处在任意一个目标点上。
输入描述:
第一行输入三个数字w, h, k (1 ≤ w, h ≤ 10, 1 ≤ k ≤ 5) ,含义在题目描述中已给出。
接下来h行,每行输入一个长度为w的字符串si,其中第i行的第j个字符表示(i, j)位置的状态。
其中,'R'代表该位置初始有一辆遥控车,'X'代表该位置有障碍物,'D'代表该位置是一个目标点,'.'代表该位置可以正常通过。
数据保证广场上的遥控车不超过4辆。
输出描述:
如果k分钟后有可能有任意一个遥控车处在任意一个目标点上,输出YES,否则输出NO。
说明
样例中,遥控车可以按下述路线移动:
.....R
...X..
..D...
....D.
R.....
...X..
..D...
....D.
R.....
R..X..
..D...
....D.
R.....
..RX..
..D...
....D.
R.....
..RX..
..R...
....D.
......
4分钟时,有一辆遥控车达到了目标点。于是输出YES
#define debug #ifdef debug #include <time.h> #include "/home/majiao/mb.h" #endif #include <iostream> #include <algorithm> #include <vector> #include <string.h> #include <map> #include <set> #include <stack> #include <queue> #define MAXN ((int)1e5+7) #define ll long long int #define QAQ (0) #include <sstream> using namespace std; int n, m, K; int dr[] = { 1, -1, 0, 0 }; //4个方向 int dc[] = { 0, 0, 1, -1 }; char mtx[16][16], tmp[16][16]/*用来模拟车的位置(0没有车,1有车)*/; struct Node { int r, c; } ; bool check(int x, int y) { //判断是否越界 return mtx[x][y]; } bool ok = false; void dfs(int level, vector<Node> v) { if(ok) return ; if(level == K) { //第level步恰好有在目标格子的车就ok=true for(int i=1; i<=n; i++) for(int k=1; k<=m; k++) if(tmp[i][k] && mtx[i][k]=='D') { ok = true; goto p; } p: return ; } for(int i=0; i<int(v.size()) && !ok; i++) { //枚举每辆车 Node& no = v[i]; //每辆车都有4个方向 for(int k=0; k<4 && !ok; k++) { int tmpr = no.r, tmpc = no.c; //移动到这个方向,直到撞墙或撞车 while(check(no.r+dr[k], no.c+dc[k]) && (mtx[no.r+dr[k]][no.c+dc[k]]!='X') && !(tmp[no.r+dr[k]][no.c+dc[k]])) { no.r += dr[k], no.c += dc[k]; } tmp[no.r][no.c] = true; tmp[tmpr][tmpc] = false; dfs(level+1, v); //递归下一步 tmp[no.r][no.c] = false; //还原现场 tmp[tmpr][tmpc] = true; no.r = tmpr, no.c = tmpc; } } } int main() { #ifdef debug freopen("test", "r", stdin); clock_t stime = clock(); #endif scanf("%d %d %d ", &m, &n, &K); vector<Node> vec; for(int i=1; i<=n; i++) { scanf("%s ", mtx[i]+1); for(int k=1; k<=m; k++) if(mtx[i][k] == 'R') vec.push_back({i, k}); } dfs(0, vec); printf("%s\n", ok ? "YES" : "NO"); #ifdef debug clock_t etime = clock(); printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC); #endif return 0; }
E 弦
链接:https://ac.nowcoder.com/acm/contest/5477/E
来源:牛客网
给定一个圆,圆上有2N个互不重叠的点。每次操作随机选择两个先前未选择过的点连一条弦,共连成N条弦,求所有弦不交的概率。
输入描述:
一行,只有一个整数N(1≤N≤107)。
输出描述:
一行,即答案。答案应以模109+7的形式输出。正式的说,令M=109+7,答案可以表示为最简分数p/q的形式,其中p和q为整数且q与M互质。输出整数x满足 0≤x<M且 x⋅q ≡ p(mod M)。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; ll qkpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } ll getInv(ll a) { return qkpow(a, mod - 2); } //求一个数的逆元 int main() { ll n; cin >> n; ll ans = 1; for (int i = 2; i <= n + 1; ++i) ans *= i, ans %= mod; ans = qkpow(2, n) * getInv(ans) % mod; cout << ans << endl; return 0; }
F排列计算
链接:https://ac.nowcoder.com/acm/contest/5477/F
来源:牛客网
天才程序员菜哭武和石头组队参加一个叫做国际排列计算竞赛 (International Competition of Permutation Calculation, ICPC) 的比赛,这个比赛的规则是这样的:
一个选手给出一个长度为 n 的排列,另一个选手给出 m 个询问,每次询问是一个形如 (l, r) 的数对,查询队友给出的排列中第 l 个数到第 r 个数的和,并将查询到的这个区间和加入总分,最后总分最高的队伍就能获胜。
石头手速很快,在比赛一开始就给出了 m 个询问;菜哭武也很强,他总是能找到最合适的排列,使得他们队的总分尽可能高。
在看比赛直播的你看到了石头给出的 m 个询问,聪明的你能不能预测出他们队伍最终的得分呢?
一个排列是一个长度为 n 的数列,其中 1 ~ n 中的每个数都在数列中恰好出现一次。比如 [1, 3, 2] 是一个排列,而 [2, 1, 4] 和 [1, 2, 3, 3] 不是排列。
输入描述:
第一行输入两个数 n (1≤n≤2×105) 和 m (1≤m≤2×105) 。
接下来 m 行,每行输入两个数 l 和 r ,代表这次查询排列中第 l 个到第 r 个的和。
输出描述:
输出一个整数,代表他们队伍总分的最大值。
说明
一个符合条件的排列是 [1,3, 6, 4, 7, 5, 2],于是最终的得分为 (1 + 3 + 6) + (6 + 4 + 7 + 5 + 2) + (7 + 5) = 46
#include<iostream> #include <cstdio> #include <algorithm> #define ll long long using namespace std; const int N = 2e5 + 5; int d[N]; int main(){ int n, m; scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++){ int l, r; scanf("%d%d", &l, &r); d[l] ++ ,d[r + 1]--; } for(int i = 1; i <= n; i++){ d[i] += d[i - 1]; } sort(d + 1, d + n + 1); ll ans = 0; for(int i = 1; i <= n; i++) ans += 1ll * d[i] * i; printf("%lld\n", ans); return 0; }
G 硬币游戏
链接:https://ac.nowcoder.com/acm/contest/5477/G
来源:牛客网
张老师和石头每年校赛都要决定谁来出最后一道题,都是通过玩游戏,每年菜哭武都能发现新的游戏。今年菜哭武选择了翻硬币游戏,谁能赢就不用出最后一道题。
有n个硬币从左到右排开,有一些是正面,有一些是反面。张老师和石头轮流选择连续最多k个(至少一个)硬币翻面,其中最右边一个硬币一定是从正面翻成反面,谁先不能行动就输掉游戏。张老师首先选择。
张老师最近忙于毕设没时间出题,也不想花时间玩游戏,想让你帮他研究一下他能否获胜。
输入描述:
第一行两个正整数n, k(1≤k≤n≤106),表示总硬币个数和同时连续最多翻转的硬币个数。
第二行一个长度是n的01字符串s,第i个字符表示从左到右第i个硬币的正反面情况,1表示正面,0表示反面。
输出描述:
输出一行,如果张老师能赢,则输出Yes,否则输出No。
输出
复制No
#include<bits/stdc++.h> using namespace std; typedef long long ll; char str[1001000]; int n; int k; int maxsg; int sg(int i){ int ans = i & (-i); return min(ans,maxsg); } int main() { cin>>n>>k; cin>>str; maxsg=1; while(k>1){ k/=2; maxsg*=2; } int sgsum = 0; for(int i=0;i<n;i++){ if(str[i]=='1') sgsum ^= sg(i+1); } if(sgsum)cout<<"Yes"<<endl; else cout<<"No"<<endl; return 0; }
H 时空栈
链接:https://ac.nowcoder.com/acm/contest/5477/H
来源:牛客网
最近,dzerzhinski刚刚学会了栈这个基础数据结构,但是他却被一道简单题难住了。
栈是一种特殊的线性表,它只能在固定的一段进行插入和删除操作。栈满足“后进先出”的性质,也就是每次出栈的元素一定是最后入栈的元素。 这道题要求实现一个栈,模拟元素的进栈和出栈和查看栈顶元素。
但是dzerzhinski的栈有时空能力,每一个操作都会首先跳转到某个时间点,然后执行这个操作,再回到当前的时间。最终状态是所有操作按照时间顺序依次执行的结果。
意识到问题的dzerzhinski发现这是一个很好的训练项目,决定让你来实现一个这样有时空能力的栈。
输入描述:
第一行一个整数n(1≤n≤2×105),表示有n个操作。
后面n行,每行表示一个操作。第一个数op表示操作类型。
op=0:入栈操作。输入三个数op,t, v,表示回到时间点t,然后整数v入栈。
op=1:出栈操作。输入两个数op,t,表示回到时间t,栈顶元素出栈。
op=2:查询栈顶元素。输入两个数op,t,表示查询时间t时的栈顶元素。
其中所有操作的时间点t满足1≤t≤109,且都不相等,保证能够有唯一的操作顺序。所有入栈整数v满足1≤v≤109。保证任意时刻不会出现空栈时出栈操作,或者在空栈的时刻查询栈顶元素操作。
输出描述:
对于每一个查询操作,输出一行,表示到当前为止的所有操作栈顶元素。
说明
部分解释:
查询7时刻栈顶的时候,之前在2时刻入栈2,在1时刻入栈1。按照时间顺序2在1之后入栈,所以结果是2;
查询3时刻的时候,所有操作是2时刻入栈2,1时刻入栈1,5时刻出栈,但是5时刻的操作不会在3时刻之前产生,所以结果还是2;
查询8时刻的时候,所有操作是2时刻入栈2,1时刻入栈1,5时刻出栈。按照时间顺序是1入栈,2入栈,2出栈,所以栈顶是1。
#include<iostream> #include <algorithm> #include <cstring> #include <stack> using namespace std; #define lson rt * 2 #define rson rt * 2 + 1 const int N = 2e5 + 100; struct node { int sum, ma; node() { sum = ma = 0; } void set(int x) { sum = ma = x; } }sa[N * 4]; node cal(node a, node b) { node c; c.sum = a.sum + b.sum; c.ma = max(a.ma + b.sum, b.ma); return c; } int n, tp; int op[N], aa[N], bb[N], has[N], rev[N]; void insert(int id, int l, int r, int rt) { if (l == r) { int i = rev[l]; if (op[i] == 0) sa[rt].set(1); else sa[rt].set(-1); return; } int m = (l + r) / 2; if (id <= m) insert(id, l, m, lson); else insert(id, m + 1, r, rson); sa[rt] = cal(sa[lson], sa[rson]); } int res; void query(node x, int l, int r, int rt) { if (l == r) { res = bb[rev[l]]; return; } int m = (l + r) / 2; if (cal(sa[rson], x).ma > 0) query(x, m + 1, r, rson); else query(cal(sa[rson], x), l, m, lson); } void query(int id, node &x, int l, int r, int rt) { if (l == r) { x = sa[rt]; if (sa[rt].sum > 0) query(x, l, r, rt); return; } int m = (l + r) / 2; if (id <= m) { query(id, x, l, m, lson); } else { query(id, x, m + 1, r, rson); if (!res) { if (cal(sa[lson], x).ma > 0) { query(x, l, m, lson); } x = cal(sa[lson], x); } } } int main() { //freopen("0.txt", "r", stdin); scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", op + i); if (op[i]) scanf("%d", aa + i); else scanf("%d%d", aa + i, bb + i); has[++tp] = i; } sort(has + 1, has + 1 + tp); tp = unique(has + 1, has + 1 + tp) - has; for (int i = 1; i <= n; i++) { aa[i] = lower_bound(has + 1, has + tp, aa[i]) - has; if (op[i] != 2) rev[aa[i]] = i; } for (int i = 1; i <= n; i++) { if (op[i] == 2) { res = 0; node x; query(aa[i], x, 1, tp, 1); printf("%d\n", res); } else insert(aa[i], 1, tp, 1); } return 0; }
I纸牌
链接:https://ac.nowcoder.com/acm/contest/5477/I
来源:牛客网
桌上有一叠共N张牌,从顶向下标号为1~N。张老师打算对这一叠牌做k次操作,其中第i次操作会将牌堆顶的牌放在牌堆中的某个位置,从而满足这张牌成为自顶向下第(i - 1) % (N - 1) + 2张牌,其中%表示取模操作。张老师想知道k次操作以后这叠牌自顶向下的编号情况,你能告诉他吗?
输入描述:
一行,两个整数N和k(2≤N≤106, 0≤k≤1018)。
输出描述:
一行共N个数,第i个数为操作k次后自顶向下第i张牌的编号。数字间用空格间隔。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e6 + 10; typedef long long ll; int n; ll k; int p[maxn], tmp[maxn]; bool vis[maxn]; void getNext(int * a, int k) { memset(tmp, 0, sizeof tmp); for(int i = 1; i <= n; ++i) tmp[(i << 1) - 1] = a[i]; int cur = 1; for(int i = 1; i <= k; ++i) { while(!tmp[cur]) ++cur; swap(tmp[cur], tmp[(i + 1) << 1]); } int tot = 0; for(int i = 1; i <= 2 * n; ++i) if(tmp[i]) a[++tot] = tmp[i]; } void getCycle(int * a, ll k) { for(int i = 1; i <= n; ++i) if(!vis[i]) { int cur = i, tot = 0; while(!vis[cur]) { tmp[++tot] = cur; vis[cur] = 1; cur = a[cur]; } tmp[0] = tmp[tot]; int shift = k % tot; for(int j = 0; j < tot; ++j) a[tmp[j]] = tmp[(j + shift) % tot]; } } int main() { cin >> n >> k; for(int i = 1; i <= n; ++i) p[i] = i; getNext(p, n - 1); getCycle(p, k / (n - 1)); getNext(p, k % (n - 1)); for(int i = 1; i <= n; ++i) cout << p[i] << ' '; cout << '\n'; return 0; } Dzerzhinski: k – k % (n – 1)部分也可以快速幂计算。整体复杂度是O(n log(k/n)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include<bits/stdc++.h> using namespace std; typedef long long ll; int arr[1001000]; int temp[2002000]; int powans[1001000]; int n; ll k; void step(int pre[],int step){ for(int i=0;i<n;i++){ temp[i*2]=pre[i]; temp[i*2+1]=0; } int now = 0; for(int i=0;i<step;i++){ while(temp[now]==0)now++; swap(temp[now],temp[(i+1)*2+1]); } now=0; for(int i=0;i<2*n;i++){ if(temp[i])pre[now++]=temp[i]; } } void mul(int a[],int b[]){ for(int i=0;i<n;i++){ temp[i]=a[b[i]-1]; } for(int i=0;i<n;i++)a[i]=temp[i]; } void powmod(int a[],ll p){ for(int i=0;i<n;i++)powans[i]=i+1; while(p){ if(p%2){ mul(powans,a); } p/=2; mul(a,a); } } int main(){ cin>>n>>k; for(int i=0;i<n;i++)arr[i]=i+1; step(arr,n-1); powmod(arr,k/(n-1)); step(powans,k%(n-1)); for(int i=0;i<n;i++){ cout<<powans[i]<<" "; } cout<<endl; return 0; }
J 斐波那契和
链接:https://ac.nowcoder.com/acm/contest/5477/J
来源:牛客网
Fib(i)表示斐波那契函数,Fib(n)=Fib(n-1)+Fib(n-2),如Fib(1)=1,Fib(2)=1,Fib(3)=2,Fib(4)=3,Fib(5)=5,Fib(6)=8。
由于结果太大,你需要把求和的结果对998,244,353取余。
输入描述:
输入一行,包含两个整数n和k(1≤n≤10
18
,1≤k≤100)
输出描述:
输出一个整数,表示求和对998,244,353取余的结果。
说明
样例解释:
1*1*Fib(1) + 2*2*Fib(2) + 3*3*Fib(3) + 4*4*Fib(4) + 5*5*Fib(5) = 196
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll modn = 998244353; struct Mat{ ll a[105][105]; Mat(){ memset(a,0,sizeof(a));\ } ll* operator[](int i){ return a[i]; } }; int W=104; Mat operator *(Mat &a, Mat &b){ Mat ans; for(int i=0;i<W;i++)for(int j=0;j<W;j++){ for(int k=0;k<W;k++) { ans[i][j] += a[i][k] * b[k][j] % modn; } ans[i][j]%=modn; } return ans; } ll C[505][505]; ll F_b[505]; ll F[505]; ll pown[505]; Mat powmod(Mat a, ll p){ Mat ans; for(int i=0;i<W;i++)ans[i][i]=1; while(p) { if (p % 2) { ans = ans * a; } p /= 2; a = a * a; } return ans; } int main() { C[0][0]=1; for(int i=0;i<500;i++){ for(int j=0;j<=i;j++){ C[i+1][j]+=C[i][j]; C[i+1][j+1]+=C[i][j]; C[i+1][j]%=modn; C[i+1][j+1]%=modn; } } ll n,k; cin>>n>>k; pown[0]=1; for(int i=1;i<=k;i++) pown[i]=pown[i-1]*(n%modn)%modn; W=k+3; Mat ans; ans[0][0]=1; ans[0][1]=1; ans[1][0]=1; ans[2][2]=1; ans[2][0]=1; ans[2][1]=1; for(int i=1;i<=k;i++){ for(int j=0;j<=i;j++){ ans[i+2][j+2]=C[i][j]; } } ans = powmod(ans,n); for(int i=0;i<=k;i++) F_b[i]=ans[i+2][1]; F[0]=F_b[0]; for(int i=1;i<=k;i++){ ll fi = F_b[i]; ll flag = 1; for(int j=0;j<i;j++){ flag = modn-flag; fi += flag * C[i][j] %modn *pown[i-j]%modn * F[j]%modn; } fi %= modn; fi *= flag; F[i]=fi%modn; } cout<<F[k]<<endl; return 0; }