题目描述
有一条宽度为 NN 的河上,小D位于坐标为 00 的河岸上,他想到达坐标为 NN 的河岸上后再回到坐标为 00 的位置。在到达坐标为 NN 的河岸之前小D只能向坐标更大的位置跳跃,在到达坐标为 NN 的河岸之后小D只能向坐标更小的位置跳跃。在河的中间有 MM 个岩石,小D希望能跳到每个岩石上恰好一次。由于小D的跳跃能力太强,小D的跳跃长度有个下限 SS ,但没有上限。现在请你判断他是否能够完成他的目标。
输入输出格式
输入格式:第一行输入两个整数 N,M,SN,M,S ,分别表示河的宽度,岩石的数量和跳跃长度的下限。
第二行输入 MM 个整数,分别表示 MM 个岩石的坐标 w_1,w_2,\cdots,w_Nw1,w2,⋯,wN 。保证 \{w_i\}{wi} 为递增序列。
如果小D可以完成他的目标,第一行输出YES
,第二行输出 M+2M+2 个数,依次表示小D跳到的石头编号。特殊的,坐标为 00 的河岸编号为 00 ,坐标为 NN 的河岸标号为 M+1M+1 。如果有多种解法,允许输出任意一种。
如果小D不能完成他的目标,第一行输出NO
。
输入输出样例
输入样例#1:6 1 3 3
输出样例#1:
YES 1 2 0
输入样例#2:
6 2 2 2 4
输出样例#2:
YES 2 3 1 0
输入样例#3:
5 2 3 2 3
输出样例#3:
NO
说明
1 \le N,S \le 1000001≤N,S≤100000
0 \le M < N0≤M<N
1 \le w_i < N1≤wi<N
题解:
首先我们考虑最靠近开头和最靠近结尾的两块岩石,如果他们离开头/结尾的距离小于
SS ,那么这块岩石将不可能被跳到,从而导致无解。
对于三个连续的岩石 i,i+1,i+2i,i+1,i+2 ,如果 w_{i+2}-w_i<Swi+2−wi<S ,由于我们只能来回一次,且每次跳到其中的一个石头上时必然不可能跳到另一个石头上,所以这种情况也会导致无解。
那么有解时我们只需要贪心地能跳就选择一个距离不小于 SS 的且最近的跳就可以了。
时间复杂度 O(N)O(N)
特别需要注意一个分类讨论的思想!!!
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e5+10;
int n, m, s, w[N], ans[N];
bool vis[N];
int main() {
scanf("%d%d%d", &n, &m, &s);
int i;
for (i = 1; i <= m; i++)
scanf("%d", &w[i]);
w[0] = 0, w[m+1] = n;
int now = 0, cnt = 0;
for (i = 1; i <= m+1; i++) {
if (w[i]-now >= s) {
ans[++cnt] = i;
now = w[i];
vis[i] = true;
}
}
if (now != n) {
printf("NO");
return 0;
}
for (i = m; i >= 0; i--) {
if (now-w[i]>=s && !vis[i]) {
ans[++cnt] = i;
now = w[i];
vis[i] = true;
}
}
if (cnt == m+2) {
printf("YES\n");
for (i = 1; i <= cnt; i++)
printf("%d ", ans[i]);
}
else printf("NO");
return 0;
}
题目描述
给定一个数字 AA ,这个 AA 由 a_1,a_2,\cdots,a_Na1,a2,⋯,aN 相乘得到。
给定一个数字 BB ,这个 BB 由 b_1,b_2,\cdots,b_Mb1,b2,⋯,bM 相乘得到。
如果 \frac{A}{B}BA 是一个质数,请输出YES
,否则输出NO
。
输入输出格式
输入格式:每个测试点包含多组数据,第一行读入一个整数 TT 表示数据组数,对于每组数据:
第一行输入两个整数 N,MN,M ,分别表示 AA 由 NN 个数字相乘得到, BB 由 MM 个数字相乘得到。
第二行输入 NN 个整数,分别表示组成 AA 的 NN 个数字。
第三行输入 MM 个整数,分别表示组成 BB 的 MM 个数字。
保证对于一个数字,其在 {b_i}bi 中出现的次数不多于在 {a_i}ai 中出现的次数。
对于每组数据:
如果 \frac{A}{B}BA 是一个质数,请输出
YES
,否则输出NO
。在输出
YES
或NO
后输出一个换行符。
输入输出样例
输入样例#1:
2 3 2 5 7 7 5 7 4 2 5 7 7 7 5 7输出样例#1:
YES NO
说明
1 \le N \le 1000001≤N≤100000
0 \le M \le N0≤M≤N
1 \le a_i,b_i \le 10^{12}1≤ai,bi≤1012
1 \le T \le 101≤T≤10
\sum N \le 100000∑N≤100000
题解:
由于保证了任何一个数字在 bb 中的出现次数不大于在 aa 中的出现次数。
那么对于每个 bb 中的数字,我们只需要将其在 aa 中删去即可。
然后考虑如何判断 aa 剩下的数字是否为质数。
我们只需要检查每个数字由几个质数组成即可。
在判断质数时,发现当前已经有两个或以上的质数了需要马上退出,否则有可能会造成TLE。
值得一提的是,由 00 个质数组成的数字(即 11 )也不是质数。
复杂度 O(n\ log\ n + \sqrt a_i )O(n log n+ai)
其实要特别注意读题,即题面中加下划线的句子。
#include<iostream>
#include<cmath>
#include<map>
#include<cstdio>
using namespace std;
const int N = 1e5+10;
map<long long, int> mp;
int t, n, m;
long long a[N], b[N], c[N];
bool judge(long long x) {
if (x==0 || x==1) return false;
int i;
for (i = 2; i <= sqrt(x); i++) {
if (!(x%i)) return false;
}
return true;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
int i, cnt = 0;
long long x=-1;
for (i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (i = 1; i <= m; i++) {
scanf("%lld", &b[i]);
mp[b[i]]++;
}
for (i = 1; i <= n; i++)
mp[a[i]]--;
for (i = 1; i <= n; i++) {
if (mp[a[i]]<0) {
cnt++;
x = a[i];
mp[a[i]]++;
}
else continue;
}
if (cnt >= 2) {
printf("NO\n");
continue;
}
else {
if (cnt == 0) {
printf("NO\n");
continue;
}
if(cnt == 1) {
if (judge(x)) printf("YES\n");
else printf("NO\n");
continue;
}
}
}
return 0;
}
参考来源:
https://www.luogu.org/problemnew/show/P4753
https://www.luogu.org/problemnew/show/P4752
https://www.luogu.org/blog/FlierKing/luo-gu-7-yue-yue-sai-ti-xie