晚安,算数级数定理
题目描述
晚上好,做题者
如果a和d为互质的正整数,那么等差数列a,a+d,a+2d,⋯包含无限多素数
这叫做狄利克雷算数级数定理
例如,从2开始并增加3的算术序列,即
2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98, … ,
包含无穷多个素数
2, 5, 11, 17, 23, 29, 41, 47, 53, 59, 71, 83, 89, … .
你的任务是编写一个程序,为给定的正整数a、d和n在这个算术序列中找到第n个素数。
输入格式
输入包含多组数据
每组输入三个正整数 a d n,意义如上所述
a≤9307,d≤346,n≤210
输出格式
对于每组数据,输出一个数,表示序列中的第n个素数
保证输出的数始终小于1e6
解题思路:
本题可以先用筛发打表得到 2~1e6 之间的所有素数,之后对于每一个等差数列,我们对于每一个 a i a_i ai 二分去查找是否是素数如果是的话个数加一,如果 个数达到n,输出,并终止循环。
代码:
#include <stdio.h>
#include <cmath>
#include <cstring>
const int N = 2E6 + 10;
int n ,d,a,cnt;
int prime[N];
bool p[N];
//打表
void init(){
memset(p,1,sizeof p);
p[0] = p[1] = 0;
cnt = 0;
for(int i = 2;i<N;++i){
if(p[i]){
prime[cnt++] = i;
for(int j = 2*i ;j<N;j+=i)
p[j] = 0;
}
}
}
int main(){
init();
while(~scanf("%d%d%d",&a,&d,&n)){
if(!a&&!n&&!d)break;
int cou = 0,i=0 ,num;
while(1){
num = a + i*d;
int l = 0,r = cnt;
bool flag = 0;
// 二分查找
while(l<r){
int mid = l+ r>>1;
if(prime[mid] == num){
flag = 1;
break;
}else if(prime[mid]>num) r = mid;
else
l = mid+1;
}
if(flag) cou ++;
if(cou == n){
printf("%d\n",num);
break;
}
i++;
}
}
return 0;
}
铁道货运
题目描述
RJ货运公司是一家从事货运业务的日本铁路公司,最近在横滨的哈泽修建了交换线路。线路布局如图1所示。
图1
货运列车由2至72节货车组成。有26种类型的货车,由26个小写字母表示,从“a”到“z”。同一类型的汽车彼此无法区分,而且每辆车的方向也不重要。因此,长度为2到72的小写字母字符串足以完全表示列车的配置。
到达交换线后,列车在任意位置分为两个子列车(在进入存储线之前)。每个子列车的方向可以反转(使用反转线)。最后,两个子列车按任意顺序连接,以形成最终配置。请注意,每个子列车的反转操作都是可选的。
例如,如果到达配置为“abcd”,则列车将分为两个子列车,分别为3:1、2:2或1:3节车厢。对于每个拆分,可能的最终配置如下所示(“+”表示最终连接位置):
[3:1]
abc+d cba+d d+abc d+cba
[2:2]
ab+cd ab+dc ba+cd ba+dc cd+ab cd+ba dc+ab dc+ba
[1:3]
a+bcd a+dcb bcd+a dcb+a
除去重复,可能有12种不同的配置。
给定到达配置,回答可以使用上述交换线路构造的不同配置的数量。
输入格式
输入包含多组数据
首先是输入一个正整数m表示一共有几组数据
接下来m行每行一个字符串(只包含小写字母),表示火车进站时的顺序
输出格式
对于每组数据,输出一个整数,表示经过反转之后一共有多少种出站方式
解题思路:
可能有数学解法,不过不会,哭。不过我们可以模拟这个过程,生成所有的结果因为最长就为72所有稳过的。模拟的话可以使用 substr() 的带分成两部分的字符串,对于这连个字符串有 4种情况,一种是 (翻,不翻),(不翻,不翻),(不翻,翻),(翻,翻)。在连接的时候又有两种情况所以对于每种分法大概有8中情况。而生成的字符串是否重复我们就可以用map来记录。
代码:
#include <stdio.h>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
int n;
string s, left, right, nowl, nowr, temp;
int sum ;
map<string, int>vis;
int main() {
while (~scanf("%d", &n)) {
while (n--) {
cin >> s;
vis.clear();
sum = 0;
for (int i = 1; i < s.size(); ++i) {
left = s.substr(0, i), right = s.substr( i );
temp = left + right ;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
temp = right + left ;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
nowl = left, nowr = right;
reverse(nowl.begin(), nowl.end()) ;
temp = nowl + right ;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
temp = right + nowl;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
nowl = left, nowr = right;
reverse(nowr.begin(), nowr.end()) ;
temp = left + nowr ;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
temp = nowr + left;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
nowl = left, nowr = right;
reverse(nowl.begin(), nowl.end()) ;
reverse(nowr.begin(), nowr.end()) ;
temp = nowl + nowr ;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
temp = nowr + nowl;
if ( vis[temp] == 0) {
sum ++;
vis[temp] = 1;
}
}
printf("%d\n", sum);
}
}
return 0;
}
冰壶游戏 2.0
题目描述
在MM-21星球上,今年的奥运会后,冰壶游戏越来越流行。但规则与我们的有些不同。游戏在冰上游戏板上进行,板上有一个方形网格。他们只用一块石头。游戏的目的是以最少的移动次数将石头从起点引导到终点。
图1显示了游戏板的示例。有些方格可能被障碍占据。有两个特殊的方格,即起点和终点,没有障碍。(起点不与终点重合)一旦石头开始移动,它将继续移动,直到碰到一个障碍物或者掉出游戏板。为了将石头带到球门,你可能需要将石头撞到一个障碍上,然后再次投掷
石头的移动遵循以下规则:
开始时,石头停在起点位置上。
石头的移动限制在水平和竖直方向。禁止对角移动。
当石头静止不动时,你可以通过扔石头使它移动。你可以把它扔到没被阻挡的任意方向(图2(a))。
抛掷后,石头将继续向同一方向移动,直到发生以下情况之一:
石头击中一块石块(图2(b)、(c))。
石头停在它击中的障碍旁边的方格上。
随后障碍消失。
石头从木板上掉了出来。
游戏失败。
石头到达了目标方格。
石头停在那里,游戏成功。
在一场比赛中,你扔石头的次数不能超过10次。如果石头在10步中没有达到目标,游戏将以失败告终。
根据以上规则,我们想知道开始时的石头是否能达到目标,如果可以,我们想知道需要的最少移动次数。
如果初始情况如图1所描述,那么我们移动4次就能到达目标方格,图3的a,b分别表示了路线和移动之后棋盘板的变化
输入格式
输入不超过100组数据,以两个用空格分开的0表示输入结束
每组数据先输入两个用空格隔开的正整数w和h分别表示棋盘的左右宽度和上下高度
2≤w≤20,1≤h≤20
接下来h行每行m个数,只包含0 1 2 3中的一个
其中
0表示该方格为空方格
1表示该方格上有障碍物
2表示起始位置
3表示目标位置
例如图1中的棋盘描述如下
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
输出格式
对于每组数据,输出最短移动次数,如果无法到达目标位置,输出-1
解题思路:
2点是起点,在dfs过程中要注意2点的特殊性,它不是1(墙),别以外只要遇到非1点总要停下。
因为冰壶砸到墙会停下,然后墙消失。所以图是随时改变的,用dfs的回溯可以很好解决,虽然这题有点像bfs,但是图随时改变,用bfs还要备份图,时间和空间复杂度大大提高。
代码:
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f;
const int N = 100;
int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
int n, m, sx, sy, res;
int mp[N][N];
void dfs(int x, int y, int step) {
if (step > 10)
return ;
for (int i = 0; i < 4; ++i) {
int xx = x + dx[i], yy = y + dy[i];
if (mp[xx][yy] == 1) // 如果第一个都是障碍就换一个方向
continue;
// 没有障碍沿着该方向滑行
while (mp[xx][yy] == 0 || mp[xx][yy] == 2 )
xx += dx[i], yy += dy[i];
// 不能滑行后的格子为-1 表示越界
if (mp[xx][yy] == -1)
continue;
// 遇到障碍停止
if (mp[xx][yy] == 1) {
// 将这个障碍去掉
mp[xx][yy] = 0;
// 因为是到障碍旁边的格子,所以回退一格
dfs(xx - dx[i], yy - dy[i], step + 1) ;
mp[xx][yy] = 1; // 回溯
}
if (mp[xx][yy] == 3) {
res = min(res, step);
continue;
}
}
}
int main() {
while (~scanf("%d%d", &m, &n)) {
if (!n && !m)
break;
memset(mp, -1, sizeof mp);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
scanf("%d", &mp[i][j]);
if (mp[i][j] == 2)
sx = i, sy = j;
}
res = INF;
dfs(sx, sy, 1);
if (res < INF)
printf("%d\n", res);
else
puts("-1");
}
return 0;
}