题目描述:
小蓝特别喜欢 2,今年是公元 2020 年,他特别高兴。他很好奇,在公元 1 年到公元 2020 年(包含)中,有多少个年份的数位中包含数字 2?
送分题 C++ 代码:
#include
using namespace std;
bool check(int x)
{
while(x)
{
if(x % 10 == 2) return true;
x /= 10;
}
return false;
}
int main()
{
int res = 0;
for(int i = 1; i <= 2020; i ++ )
if(check(i)) res ++;
cout << res << endl;
return 0;
}
// 563
题目描述:
小蓝在一张无限大的特殊画布上作画。
这张画布可以看成一个方格图,每个格子可以用一个二维的整数坐标表示。
小蓝在画布上首先点了一下几个点:(0, 0), (2020, 11), (11, 14), (2000, 2000)。
只有这几个格子上有黑色,其它位置都是白色的。
每过一分钟,黑色就会扩散一点。具体的,如果一个格子里面是黑色,它
就会扩散到上、下、左、右四个相邻的格子中,使得这四个格子也变成黑色
(如果原来就是黑色,则还是黑色)。
请问,经过 2020 分钟后,画布上有多少个格子是黑色的。
本人刚看到这个题,第一反应就是 bfs, 但是着手开始写代码时发现了下面两个问题
st[ ]
状态数组,来看他是否已经被染过色了,完美解决了这个问题C++代码:
#include
#include
#define x first
#define y second
using namespace std;
const int N = 10010;
struct node{
int x, y, c;
}t, s;
queue<node> q;
bool st[N][N];
long long ans;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int main()
{
q.push({0 + 2100, 0 + 2100, 0});
q.push({2020 + 2100, 11 + 2100, 0});
q.push({11 + 2100, 14 + 2100, 0});
q.push({2000 + 2100, 2000 + 2100, 0});
ans = 4;
st[0 + 2100][0 + 2100] = st[2020 + 2100][11 + 2100] = true;
st[11 + 2100][14 + 2100] = st[2000 + 2100][2000 + 2100] = true;
while(!q.empty())
{
t = q.front();
q.pop();
s.c = t.c + 1;
for(int i = 0; i < 4; i ++ )
{
s.x = t.x + dx[i], s.y = t.y + dy[i];
if(s.x >= 0 && s.y >= 0 && !st[s.x][s.y] && s.c <= 2020)
{
st[s.x][s.y] = true;
ans ++;
q.push(s);
}
}
}
cout << ans << endl;
return 0;
}
// 20312088
题目描述:
定义阶乘 n ! = 1 × 2 × 3 × ⋅ ⋅ ⋅ × n n! = 1 × 2 × 3 × · · · × n n!=1×2×3×⋅⋅⋅×n。
请问 100 ! 100! 100! (100 的阶乘)有多少个正约数。
这个题会用到数论的知识,任意一个正整数 X 都可以表示成若干个质数乘积的形式,即 X = p 1 α 1 ∗ p 2 α 2 … … ∗ p k α k X = p_1^{α_1} ∗ p_2^{α_2} …… ∗ p_k^{α_k} X=p1α1∗p2α2……∗pkαk
约数个数 S = ( a 1 + 1 ) ( a 2 + 1 ) … … ( a k + 1 ) S = (a_1 + 1)(a_2 + 1)……(a_k + 1) S=(a1+1)(a2+1)……(ak+1)
C++代码:
#include
#include
#include
using namespace std;
const int N = 110;
long long res = 1;
int a[N]; //预处理a数组就可以求出我们的指数序列
int main()
{
for(int i = 2; i <= 100; i ++ )
{
int t = i;
for(int j = 2; j <= t; j ++ )
{
//如果 t可以整除j 那么有关于j的约数个数 ++
while(t % j == 0)
{
t /= j;
a[j] ++;
}
}
}
for(int i = 2; i <= 100; i ++ )
if(a[i]) res = res * (a[i] + 1);
cout << res << endl;
return 0;
}
// 39001250856960000
题目描述:
小蓝特别喜欢单调递增的事物。
在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺
序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。
例如,在字符串 lanqiao 中,如果取出字符 n 和 q,则 nq 组成一个单
调递增子序列。类似的单调递增子序列还有 lnq、i、ano 等等。
小蓝发现,有些子序列虽然位置不同,但是字符序列是一样的,例如取第
二个字符和最后一个字符可以取到 ao,取最后两个字符也可以取到 ao。小蓝
认为他们并没有本质不同。
对于一个字符串,小蓝想知道,本质不同的递增子序列有多少个?
例如,对于字符串 lanqiao,本质不同的递增子序列有 21 个。它们分别
是 l、a、n、q、i、o、ln、an、lq、aq、nq、ai、lo、ao、no、io、lnq、
anq、lno、ano、aio。
请问对于以下字符串(共 200 个小写英文字母,分四行显示):(如果你把
以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在
试题目录下有一个文件 inc.txt,内容与下面的文本相同)
tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl
本质不同的递增子序列有多少个?
我只想到了线性dp的做法:
f[i]
表示的就是以i
结尾的前面所有的递增子串的个数
状态方程:
if(s[i] > s[j]) f[i] += f[j];
这里学要注意的就是题目中说到了有些子序列虽然位置不同,但是字符序列是一样的,例如取第二个字符和最后一个字符可以取到 ao,取最后两个字符也可以取到 ao。小蓝
所以必需要考虑会计算重复的问题,所以
if(s[i] == s[j]) f[i] -= f[j];
C++ 代码:
#include
using namespace std;
const int N = 1000;
int f[N];
string ss;
int main()
{
ss = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
for(int i = 0; i < ss.size(); i ++ )
{
f[i] = 1;
for(int j = 0; j < i;j ++ )
{
if(ss[i] > ss[j]) f[i] += f[j];
if(ss[i] == ss[j]) f[i] -= f[j];
}
}
long long res = 0;
for(int i = 0; i < ss.size(); i ++ ) res += f[i];
cout << res << endl;
return 0;
}
// 3616159
题目描述:
小蓝有一条玩具蛇,一共有 16 节,上面标着数字 1 至 16。每一节都是一个正方形的形状。相邻的两节可以成直线或者成 90 度角。小蓝还有一个 4 × 4 的方格盒子,用于存放玩具蛇,盒子的方格上依次标着字母 A 到 P 共 16 个字母。小蓝可以折叠自己的玩具蛇放到盒子里面。他发现,有很多种方案可以将玩具蛇放进去。
下图给出了两种方案:
请帮小蓝计算一下,总共有多少种不同的方案。如果两个方案中,存在玩具蛇的某一节放在了盒子的不同格子里,则认为是不同的方案。
本质就是dfs,这里有一个小技巧,很多时候,dfs和dp其实很像,导致我们常常拿不准到底用那种方法来解题,其实仔细想想,他们的差别其实很大,因为dp的话,是这个题可以分组考虑,而相反dfs就很多情况下是按个枚举,回到这个题,就比较有意思了,因为我们既可以考虑dp,也可以用dfs,这里推荐dfs,因为代码好懂。我们直接枚举蛇头的位置,然后开始dfs蛇身,当蛇身长度为16时,就可以答案++
了, 在蓝桥杯中,这样的题算是送分题了。
C++ 代码:
#include
#include
#include
using namespace std;
const int N = 5;
int ans;
bool st[N][N];
int dx[4] = {-1, 0, 1, 0} , dy[4] = {0, 1, 0, -1};
void dfs(int x, int y, int u)
{
if(x >= 4 || y >= 4 || x < 0 || y < 0) return;
if(u == 16) ans ++;
for(int i = 0; i < 4; i ++ )
{
int tx = x + dx[i], ty = y + dy[i];
if(!st[tx][ty])
{
st[tx][ty] = true;
dfs(tx, ty, u + 1);
st[tx][ty] = false;
}
}
}
int main()
{
for(int i = 0; i < 4; i ++ )
for(int j = 0; j < 4; j ++ )
{
memset(st, false, sizeof st);
st[i][j] = true;
dfs(i, j, 1);
st[i][j] = false;
}
cout << ans << endl;
return 0;
}
// 552
题目描述:
皮亚诺曲线是一条平面内的曲线。
下图给出了皮亚诺曲线的 1 1 1 阶情形,它是从左下角出发,经过一个 3 × 3 3 × 3 3×3 的方格中的每一个格子,最终到达右上角的一条曲线。下图给出了皮亚诺曲线的2 阶情形,它是经过一个 3 2 × 3 2 3^2 × 3^2 32×32 的方格中的每一
个格子的一条曲线。它是将 1 阶曲线的每个方格由 1 阶曲线替换而成。
下图给出了皮亚诺曲线的 3 阶情形,它是经过一个 3 3 × 3 3 3^3 × 3^3 33×33 的方格中的每一个格子的一条曲线。它是将 2 阶曲线的每个方格由 1 阶曲线替换而成。皮亚诺曲线总是从左下角开始出发,最终到达右上角。我们将这些格子放到坐标系中,对于 k 阶皮亚诺曲线,
左下角的坐标是 ( 0 , 0 ) (0, 0) (0,0),
右上角坐标是 ( 3 k − 1 , 3 k − 1 ) (3^k − 1, 3^k − 1) (3k−1,3k−1),
右下角坐标是$ (3^k − 1, 0) , 左 上 角 坐 标 是 , 左上角坐标是 ,左上角坐标是 (0, 3^k − 1) $。
给定 k 阶皮亚诺曲线上的两个点的坐标,请问这两个点之间,如果沿着皮亚诺曲线走,距离是到少?
输入格式:
输入的第一行包含一个正整数 k,皮亚诺曲线的阶数。
第二行包含两个整数 x1, y1,表示第一个点的坐标。
输出格式
输出一个整数,表示给定的两个点之间的距离。
样例输入
1
0 0
2 2
样例输出
8
样例输入
2
0 2
0 3
样例输出
13
评测用例规模与约定
对于 30% 的评测用例,0 ≤ k ≤ 10。
对于 50% 的评测用例,0 ≤ k ≤ 20。
对于所有评测用例, 0 ≤ k ≤ 100 , 0 ≤ x 1 , y 1 , x 2 , y 2 < 3 k , x 1 , y 1 , x 2 , y 2 ≤ 1018 0 ≤ k ≤ 100, 0 ≤ x1, y1, x2, y2 < 3^k, x1, y1, x2, y2 ≤1018 0≤k≤100,0≤x1,y1,x2,y2<3k,x1,y1,x2,y2≤1018。
数据保证答案不超过 1018。
这个题是找规律的题,不是很好做,我们慢慢来分析,大致思路就是把高阶的皮亚诺曲线映射为一阶皮亚诺,再去找不同皮亚诺的坐标变换。
return ans + cacl(n - 1, pt);
//根据皮亚诺曲线的阶数,将要求确定的点映射
//到一个一阶皮亚诺曲线上
LL len = pow(3, n - 1);
LL ans = 0;
PII t(p.x / len, p.y / len); //映射到一阶曲线上的点的坐标
LL op = 0;
LL tx = p.x, ty = p.y;
// 根据皮亚诺曲线在一个九宫格中的分布,将每个格点进行分类,为九个点
// 可以画图进行理解
if(t.x == 0) op = t.y + 1;
else if(t.x == 1)
{
if(t.y == 2) op = 4;
if(t.y == 1) op = 5;
if(t.y == 0) op = 6;
}
else op = t.y + 7;
//就是从(0,0)点到 op所在格点要走的的步数
ans += len * len * (op - 1);
//递归结束
if(n == 1) return ans;
PII pt;
// 接下来的就是升阶后的坐标的转换,可以找,2阶和1阶对比来进行转化
// 因为递归的存在,所以进行转化时,你所求点的坐标最后转化后就是以
// 这个点所在的九宫格的左下角的那个点为(0,0),所做的转化
// 可以分组对称着来看
// 中心点
if(op == 5) pt = {-(tx - 2 * len + 1), - (ty - 2 * len + 1)};
//正对角线
if(op == 3) pt = {ty, ty - 2 * len};
if(op == 7) pt = {tx - 2 * len, ty};
if(op == 2) pt = {-(tx - len + 1), ty - len};
if(op == 6) pt = {tx - len, -(ty - len + 1)};
//反对角线
if(op == 9) pt = {tx - 2 * len, ty - 2 * len};
if(op == 1) pt = {tx, ty};
if(op == 4) pt = {tx - len, -(ty - 3 * len + 1)};
if(op == 8) pt = {-(tx - 3 * len + 1), ty - len};
C++ 代码:
#include
#include
#include
#include
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
LL cacl(LL n, PII p)
{
LL len = pow(3, n - 1);
LL ans = 0;
PII t(p.x / len, p.y / len);
LL op = 0;
LL tx = p.x, ty = p.y;
if(t.x == 0) op = t.y + 1;
else if(t.x == 1)
{
if(t.y == 2) op = 4;
if(t.y == 1) op = 5;
if(t.y == 0) op = 6;
}
else op = t.y + 7;
ans += len * len * (op - 1);
if(n == 1) return ans;
PII pt;
if(op == 5) pt = {-(tx - 2 * len + 1), - (ty - 2 * len + 1)};
if(op == 3) pt = {ty, ty - 2 * len};
if(op == 7) pt = {tx - 2 * len, ty};
if(op == 2) pt = {-(tx - len + 1), ty - len};
if(op == 6) pt = {tx - len, -(ty - len + 1)};
if(op == 9) pt = {tx - 2 * len, ty - 2 * len};
if(op == 1) pt = {tx, ty};
if(op == 4) pt = {tx - len, -(ty - 3 * len + 1)};
if(op == 8) pt = {-(tx - 3 * len + 1), ty - len};
return ans + cacl(n - 1, pt);
}
int main()
{
LL n, x1, x2, y1, y2;
scanf("%d%d%d%d%d", &n, &x1, &y1, &x2, &y2);
PII fi(x1, y1), se(x2, y2);
LL res = abs(cacl(n, fi) - cacl(n, se));
cout << res << endl;
return 0;
}
题目描述:
L 星球游乐园非常有趣,吸引着各个星球的游客前来游玩。小蓝是 L 星球游乐园的管理员。为了更好的管理游乐园,游乐园要求所有的游客提前预约,小蓝能看到系统上所有预约游客的名字。每个游客的名字由一个大写英文母开始,后面跟0 个或多个小写英文字母。游客可能重名。小蓝特别喜欢递增的事物。今天,他决定在所有预约的游客中,选择一部分游客在上午游玩,其他的游客都在下午游玩,在上午游玩的游客要求按照预约的顺序排列后,名字是单调递增的,即排在前面的名字严格小于排在后面的名字。
一个名字 A 小于另一个名字 B 是指:存在一个整数 i,使得 A 的前 i 个字母与 B 的前 i 个字母相同,且 A 的第 i+ 1 个字母小于 B 的第 i+ 1 个字母(如果 A 不存在第 i + 1 个字母且 B 存在第 i + 1 个字母,也视为 A 的第 i + 1 字母小于 B 的第 i + 1 个字母)作为小蓝的助手,你要按照小蓝的想法安排客,同时你又希望上午有尽量多的游客游玩,请告诉小蓝让哪些游客上午玩。如果方案有多种,请输出上午游玩的第一个游客名字最小的方案。如此时还有多种方案,请输出第一个游客名字最小的前提下第二个游客名字最的方案。如果仍然有多种,依此类推选择第三个、第四个……游客名字最小的方案。
输入格式
输入包含一个字符串,按预约的顺序给出所有游客的名字,相邻的游客名字之间没有字符分隔。
输出格式
按预约顺序输出上午游玩的游客名单,中间不加任何分隔字符。
样例输入
WoAiLanQiaoBei
样例输出
AiLanQiao
评测用例规模与约定
对于 20% 的评测数据,输入的总长度不超过 20 个字母。
对于 50% 的评测数据,输入的总长度不超过 300 个字母。
对于 70% 的评测数据,输入的总长度不超过 10000 个字母。
对于所有评测数据,每个名字的长度不超过 10 个字母,输入的总长度不超
过 1000000 个字母。
该题只想到了 O ( n 2 ) O(n^2) O(n2)的做法即线性dp,很明显只能拿一半的分,本题要拿满分肯定要是 O ( n ) 或 O ( n l o g n ) O(n) 或 O(nlog_n) O(n)或O(nlogn)的做法,小编太菜了,还在努力学习中,日后如果可以想出满分做法,再来补充。那么开始考虑线性dp的做法
//处理输入的字符串,把每个名字存入字符串数组中
for(int i = 0; i < s.size(); i ++ )
{
//如果s[i]实在A~Z之间时,如果s[i]不是一个新名字的开头那就继续++,如果是的话
//就放入到名字数组中idx++,并将t串赋空
//如果s[i] 不在A~Z之间,就继续累加t串就可以
if(s[i] >= 'A' && s[i] <= 'Z' )
{
if(!fa)
t += s[i];
else
{
e[idx ++] = t;
t = "";
t += s[i];
fa = false;
}
fa = true;
}
else t += s[i];
// 最后,不会出现大写字母了,仍要把累加的t串作为最后一个名字放入到名字数组中
if(i == s.size() - 1) e[idx ++] = t;
}
f[i] = max(f[i], f[j] + 1)
,表示的是以s[i]
结尾,前一个是s[j]
的和当前已经求得的以s[i]
结尾的中最大值。path[i]
来记录以i结尾的子串的前一个串,且满足上升序列要求的下标位置,最后在dfs求输出一下就可以了,或者可以循环输出。#include
#include
#include
#include
using namespace std;
const int N = 1000010;
string e[N];
int idx;
bool fa = false;
int f[N], path[N];
void dfs(int u)
{
if(u == 0) return;
dfs(path[u]);
cout<< e[u];
}
int main()
{
string s, t; cin >> s;
//处理输入的字符串,把每个名字存入字符串数组中
for(int i = 0; i < s.size(); i ++ )
{
if(s[i] >= 'A' && s[i] <= 'Z' )
{
if(!fa)
t += s[i];
else
{
e[idx ++] = t;
t = "";
t += s[i];
fa = false;
}
fa = true;
}
else t += s[i];
if(i == s.size() - 1) e[idx ++] = t;
}
// dp 求最大上升子序列
int maxx = -1, pos;
for(int i = 0; i < idx; i ++ )
{
f[i] = 1;
for(int j = 0;j < i;j ++ )
{
if(e[j] < e[i])
{
f[i] = max(f[i], f[j] + 1);
path[i] = j;
if(maxx < f[i])
{
//记录位置
maxx = f[i];
pos = i;
}
}
}
}
// for(int i = 0 ;i < 100; i ++ )
// if(path[i] != 0) cout << "i == " << i << " " << path[i] << endl;
// cout << "pos :" << pos << endl;
// 遍历最大上升子序列
dfs(pos);
return 0;
}
问题描述:
有 n 位同学同时找老师答疑。每位同学都预先估计了自己答疑的时间。老师可以安排答疑的顺序,同学们要依次进入老师办公室答疑。一位同学答疑的过程如下:
一位同学离开办公室后,紧接着下一位同学就可以进入办公室了。答疑从 0 时刻开始。老师想合理的安排答疑的顺序,使得同学们在课程群里面发消息的时刻之和最小。
输入格式
输入第一行包含一个整数 n,表示同学的数量。接下来 n 行,描述每位同学的时间。其中第 i 行包含三个整数 si, ai, ei,意义如上所述。
输出格式
输出一个整数,表示同学们在课程群里面发消息的时刻之和最小是多少。
样例输入
3
10000 10000 10000
20000 50000 20000
30000 20000 30000
样例输出
280000
样例说明
按照 1, 3, 2 的顺序答疑,发消息的时间分别是 20000, 80000, 180000。
评测用例规模与约定
对于 30% 的评测用例,1 ≤ n ≤ 20。
对于 60% 的评测用例,1 ≤ n ≤ 200。
对于所有评测用例, 1 ≤ n ≤ 1000 , 1 ≤ s i ≤ 60000 , 1 ≤ a i ≤ 1000000 1 ≤ n ≤ 1000,1 ≤ s_i ≤ 60000,1 ≤ a_i ≤ 1000000 1≤n≤1000,1≤si≤60000,1≤ai≤1000000,
e i ∈ ( 10000 , 20000 , 30000 ) , 即 e i 一 定 是 10000 , 20000 , 30000 之 一 。 e_i ∈ (10000, 20000, 30000),即 e_i 一定是 10000,20000,30000 之一。 ei∈(10000,20000,30000),即ei一定是10000,20000,30000之一。
贪心策略,很简单让总时间花费最小的先问,这样后面每个人等待的时间就最小,所以直接排序。时间复杂度 O ( n l o g n ) O(nlog_n) O(nlogn)应该是可以得到满分的。
C+代码:
#include
#include
#include
#include
typedef long long LL;
using namespace std;
const int N = 1010;
int n;
struct tp{
int a, b, c;
int sum;
bool operator < (const tp &tt) const
{
return sum < tt.sum;
}
}t[N];
LL res = 0;
int main()
{
cin >> n;
int a, b, c;
for(int i = 0; i < n; i ++ )
{
scanf("%d%d%d", &a, &b, &c);
t[i] = {a, b, c, a + b + c};
}
sort(t, t + n);
for(int i = 0 ; i < n; i ++) cout << t[i].sum << endl;
int mo[N] = {0};
for(int i = 0; i < n; i ++ ) mo[i + 1] = t[i].sum + mo[i];
for(int i = 0; i < n; i ++ ) res += t[i].a + t[i].b + mo[i];
cout << res << endl;
return 0;
}
不会!跳过
问题描述
小蓝在玩一个叫质数行者的游戏。游戏在一个 n × m × w 的立体方格图上进行,从北到南依次标号为第 1 行到第 n 行,从西到东依次标号为第 1 列到第m 列,从下到上依次标号为第 1 层到第 w 层。小蓝要控制自己的角色从第 1 行第 1 列第 1 层移动到第 n 行第 m 列第 w层。每一步,他可以向东走质格、向南走质数格或者向上走质数格。每走到一个位置,小蓝的角色要稍作停留。在游戏中有两个陷阱,分别为第 r1 行第 c1 列第 h1 层和第 r2 行第 c2列第h2 层。这两个陷阱的位置可以跨过,但不能停留。也就是说,小蓝不控制角色某一步正好走到陷阱上,但是某一步中间跨过了陷阱是允许的。小蓝最近比较清闲,因此他想用不同的走法来完成这个游戏。所谓两个走法不同,是指小蓝稍作停留的位置集合不同。请帮小蓝计算一下,他总共有多少种不同的走法。提示:请注意内存限制,如果你的程序运行时超过内存限制将不得分。
输入格式
输入第一行包含两个整数 n, m, w,表示方格图的大小。
第二行包含 6 个整数,r1, c1, h1, r2, c2, h2,表示陷阱的位置。
输出格式
输出一行,包含一个整数,表示走法的数量。答案可能非常大,请输出答
案除以 1000000007 的余数。
样例输入
5 6 1
3 4 1 1 2 1
样例输出
11
样例说明
用 (r, c, h) 表示第 r 行第 c 列第 h 层,可能的走法有以下几种:
1. (1, 1, 1) − (1, 3, 1) − (1, 6, 1) − (3, 6, 1) − (5, 6, 1)。
2. (1, 1, 1) − (1, 3, 1) − (3, 3, 1) − (3, 6, 1) − (5, 6, 1)。
3. (1, 1, 1) − (1, 3, 1) − (3, 3, 1) − (5, 3, 1) − (5, 6, 1)。
4. (1, 1, 1) − (3, 1, 1) − (3, 3, 1) − (3, 6, 1) − (5, 6, 1)。
5. (1, 1, 1) − (3, 1, 1) − (3, 3, 1) − (5, 3, 1) − (5, 6, 1)。
6. (1, 1, 1) − (3, 1, 1) − (5, 1, 1) − (5, 3, 1) − (5, 6, 1)。
7. (1, 1, 1) − (3, 1, 1) − (5, 1, 1) − (5, 4, 1) − (5, 6, 1)。
8. (1, 1, 1) − (1, 4, 1) − (1, 6, 1) − (3, 6, 1) − (5, 6, 1)。
9. (1, 1, 1) − (1, 6, 1) − (3, 6, 1) − (5, 6, 1)。
10. (1, 1, 1) − (3, 1, 1) − (3, 6, 1) − (5, 6, 1)。
11. (1, 1, 1) − (3, 1, 1) − (5, 1, 1) − (5, 6, 1)。
评测用例规模与约定
对 于 30 对 于 60 对 于 所 有 评 测 用 例 , 1 ≤ n , m , w ≤ 1000 , 1 ≤ r 1 , r 2 ≤ n , 1 ≤ c 1 , c 2 ≤ m , 1 ≤ h 1 , h 2 ≤ w , 陷 阱 不 在 起 点 或 终 点 , 两 个 陷 阱 不 同 。 对于 30% 的评测用例 1 ≤ n, m,w ≤ 50。 对于 60% 的评测用例 1 ≤ n, m,w ≤ 300。 对于所有评测用例,1 ≤ n, m, w ≤ 1000,1 ≤ r_1,r_2 ≤ n, 1 ≤ c_1, c_2 ≤ m, 1 ≤ h_1, h_2 ≤ w,陷阱不在起点或终点,两个陷阱不同。 对于30对于60对于所有评测用例,1≤n,m,w≤1000,1≤r1,r2≤n,1≤c1,c2≤m,1≤h1,h2≤w,陷阱不在起点或终点,两个陷阱不同。
dfs + 素数筛
先通过素数筛求出 小于r,c,h 中最大值的所有质数,然后再三个方向进行dfs遍历就可以了,同样是只能拿部分分。
C++ 代码:
#include
#include
using namespace std;
const int N = 310, mod = 1e9 + 7;
int r1, c1, h1;
int r2, c2, h2;
int g[N][N][N];
bool st[N][N][N];
int n, m, w;
int primes[N], idx;
bool stp[N];
int res;
void get_prime(int x)
{
for(int i = 2; i <= n; i ++ )
{
if(!stp[i]) primes[idx ++ ] = i;
for(int j = 0; primes[j] <= n / i; j ++ )
{
stp[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
bool check(int x,int y,int h)
{
if(x == r1 && y == c1 && h == h1) return false;
if(x == r2 && y == c2 && h == h2) return false;
return true;
}
void dfs(int x, int y, int h)
{
if(x == n && y == m && h == w)
{
res = (res + 1) % mod;
return;
}
for(int i = 0;i < idx; i ++ )
{
if(x + primes[i] <= n && check(x + primes[i], y, h))
{
st[x + primes[i]][y][h] = true;
dfs(x + primes[i], y, h);
st[x + primes[i]][y][h] = false;
}
if(y + primes[i] <= m && check(x, y + primes[i], h))
{
st[x][y + primes[i]][h] = true;
dfs(x, y + primes[i], h);
st[x][y + primes[i]][h] = false;
}
if(h + primes[i] <= h&& check(x, y, h + primes[i]))
{
st[x][y][h + primes[i]] = true;
dfs(x, y, h + primes[i]);
st[x][y][h + primes[i]] = false;
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &w);
scanf("%d%d%d%d%d%d", &r1, &c1, &h1, &r2, &c2, &h2);
int maxx = max(max(n, m), w);
get_prime(maxx);
//for(int i = 0; i < maxx; i ++ ) cout << primes[i] << ' ';
st[1][1][1] = true;
dfs(1, 1, 1);
st[1][1][1] = false;
cout << res << endl;
return 0;
}
总结:自己太菜了