洛谷一些题

大概每日N题(非课内难度)

被工大杯的各位julao打击到了的L同学决定大概每天刷题, 绝对不咕, 如果没有人问课内的问题的话就在这里写点竞赛难度的题吧.

题1 P1192 台阶问题

题目描述

有N级的台阶,你一开始在底部,每次可以向上迈最多K级台阶(最少1级),问到达第N级台阶有多少种不同方式。

输入格式

两个正整数N,K。

输出格式

一个正整数,为不同方式数,由于答案可能很大,你需要输出ansbmod 100003后的结果。

题解

复杂度O(nk).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;
#define MAXN 100010
#define MOD 100003
int n,k;
int data[MAXN] = {1, 0};
int main(){
cin>>n>>k;
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= k; ++ j){
if(i-j>=0){
data[i] += data[i-j];
}
}
data[i] %= MOD;
}
cout<<data[n]<<endl;
return 0;
}

题2 P1025 数的划分

题目描述

1
2
3
4
5
6
7
8
9
将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

例如:n=7,k=3,下面三种分法被认为是相同的。

1,1,5;
1,5,1;
5,1,1;

问有多少种不同的分法。

输入格式

n,kn,k (6<n≤200, 2≤k≤6)

输出格式

1个整数,即不同的分法。

题解

DFS暴搜即可, 划分的时候保证升序防止出现重复.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
#define MAXN 210
#define MAXM 7
int n,k;
int classmateL(int n, int k, int min){
//cout<<"Stepping In "<<n<<" "<<k<<endl;
if(k == 1){
return 1;
}
int ans = 0;
for(int i = min; i <= n / k; ++ i ){
ans += classmateL(n - i, k - 1, i);
}
//cout<<"Stepping Out "<<n<<" "<<k<<" "<<ans<<endl;
return ans;
}
int main(){
cin>>n>>k;
cout<<classmateL(n,k,1);
return 0;
}

题3 P1057 传球游戏

题目描述

1
2
3
4
5
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。

游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没有传出去的那个同学就是败者,要给大家表演一个节目。

聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了mm次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->11->3->2->1,共2种。

输入格式

一行,有两个用空格隔开的整数n,m(3≤n≤30,1≤m≤30)。

输出格式

1个整数,表示符合题意的方法数。

题解

先想着DFS暴搜, 发现T了, 才想起来复杂度是O(m^2).

于是DP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
int n,m,dp[50][50];
int main() {
cin>>n>>m;
dp[0][0]=1;
for(int i=0;i<m;i++) {
for (int j = 0; j < n; j++) {
if (dp[i][j]) {
dp[i + 1][(j - 1 + n) % n] += dp[i][j];
dp[i + 1][(j + 1) % n] += dp[i][j];
}
}
}
cout<<dp[m][0];
return 0;
}

题4 P1996 约瑟夫问题

题目描述

n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号.

输入格式

n m

输出格式

出圈的编号

题解

本身想暴力, 结果莫名re和tle, 只得使用队列.

STL大法好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <queue>
using namespace std;
int main() {
int n,m;
cin>>n>>m;
queue<int> que;
for(int i = 1; i <= n; ++ i){
que.push(i);
}
for(int i = 1; i <= n; ++ i){
for(int j = 1; j < m; ++ j){
que.push(que.front());
que.pop();
}
cout<<que.front()<<" ";
que.pop();
}
return 0;
}