JXNU暑期选拔赛题解

时间:2022-12-20 22:44:49

1001 最小的数
思路:因为集合中有n个数(每个数都是由i个不同的质因子组成的最小的数),所以通过素数筛选法选出前n个素数,因为要是不同的质因子,所以最小的数就是i个相对小的素数相乘,然后把乘积取余放入set中,之后直接查找就好了

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 2225
#define M 1000000
#define LL __int64
#define inf 0x3f3f3f3f
#define lson l,mid,ans<<1
#define rson mid+1,r,ans<<1|1
using namespace std;
const LL mod = 1e9 + 7;
const double eps = 1e-9;
LL num[N];
int flag[M];
set<LL> s;
int main() {
cin.sync_with_stdio(false);
s.clear();
LL n, q;
cin >> n;
q = 0;
memset(flag, 0, sizeof(flag));
for (int i = 2; i < M; i++) {
if (!flag[i]) {
num[q++] = i;
if (q == n) {
break;
}
for (int j = i + i; j < M; j += i) {
flag[j] = 1;
}
}
}
s.insert(num[0]);
for (int i = 1; i < n; i++) {
num[i] *= num[i - 1];
num[i] %= mod;
s.insert(num[i]);
}
cin >> q;
while (q--) {
cin >> n;
n %= mod;
if (s.find(n) != s.end()) {
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
}
return 0;
}

1002 不安全序列
思路:递推吧,因为每一个情况都是由前一个情况转变过来的,所以用一个dp数组去存每个情况相应的值,每一层的意思如下:(i为当前序列的长度)

dp[i][0]没有三个连续U的序列最右边为L
dp[i][1]没有三个连续U的序列最右边有一个U
dp[i][2]没有三个连续U的序列最右边有两个连续的U
dp[i][3]有三个连续的U的序列

结合每个情况可以发现

  1. dp[i][0]可以由dp[i-1][0]+dp[i-1][1]+dp[i-1][2]转变过来,因为前一状态只要不是有了3个连续的U的序列,在最右边加一个L就可以形成
  2. dp[i][1]可以由dp[i - 1][0]转变过来,因为只能是在最右边没有U的序列加上个U形成
  3. dp[i][2]可以由dp[i - 1][1]转变过来,因为只能是在最右边有一个U的序列加上个U形成
  4. dp[i][3]可以由dp[i - 1][3] * 2 + dp[i - 1][2]转变过来,因为如果原本就是有连续3个U的序列最右边加上什么都是该情况,然后也可以在最右边有两个U的序列加上个U形成

结合上面的思路就能写出这题了

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 35
#define M 1000000
#define LL __int64
#define inf 0x3f3f3f3f
#define lson l,mid,ans<<1
#define rson mid+1,r,ans<<1|1
using namespace std;
const LL mod = 1e9 + 7;
const double eps = 1e-9;
LL dp[N][4];
void init() {
dp[1][0] = 1;
dp[1][1] = 1;
dp[1][2] = 0;
dp[1][3] = 0;
for (int i = 2; i <= 37; i++) {
dp[i][0] = dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2];
dp[i][1] = dp[i - 1][0];
dp[i][2] = dp[i - 1][1];
dp[i][3] = dp[i - 1][3] * 2 + dp[i - 1][2];
}
}
int main() {
cin.sync_with_stdio(false);
int n;
init();
while (cin >> n&&n) {
cout << dp[n][3] << endl;
}
return 0;
}

1003 壮壮的数组
思路:数学题目,因为c序列是由a,b序列中的数构成的,每一位不是选a[i],就是选b[i],但是因为数据量比较大所以不能直接模拟去写,举个例子:

A序列:a1 a2
B序列:b1 b2
C序列:(1)a1 b2 (2)a2 b1
K值得总和:a1 * b2+a2 * b1
(a1+b1) * (a2+b2) = a1 * a2+a1 * b2+b1 * a2+b1 * b2
K=(a1+b1) * (a2+b2)-(a1 * a2+b1 * b2)(因为不让全为A或者B)

所以可以通过这个方式计算出K的值

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 100010
#define M 1000000
#define LL __int64
#define inf 0x3f3f3f3f
#define lson l,mid,ans<<1
#define rson mid+1,r,ans<<1|1
using namespace std;
const LL mod = 1e9 + 7;
const double eps = 1e-9;
LL a[N], b[N];
int main() {
cin.sync_with_stdio(false);
int n;
LL sum, ans, cnt;
while (cin >> n) {
ans = 1;
for (int i = 0; i < n; i++) {
cin >> a[i];
ans *= a[i];
ans %= mod;
}
cnt = 1;
for (int i = 0; i < n; i++) {
cin >> b[i];
cnt *= b[i];
cnt %= mod;
}
sum = 1;
for (int i = 0; i < n; i++) {
sum *= (a[i] + b[i]);
sum %= mod;
}
sum = (sum + mod - ans + mod - cnt) % mod;
cout << sum << endl;
}
return 0;
}

1004 涛涛的Party
CF上的原题,但是我把他的难度降低了一点,原题地址,原题是如果单独参加也行,只要没有同一个朋友圈的两个及以上但是不是整个朋友圈的全部人参加就是允许的。
思路:就是并查集+01背包,因为他必须要是一个朋友圈的人参加才会去,并且朋友的朋友就是自己的朋友,所以通过并查集去得到这个朋友圈,把这个朋友圈中的所有美女的食量和魅力值都叠加起来,求01背包就好了

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define LL long long
#define N 1100
#define M 50010
#define inf 0x3f3f3f3f
using namespace std;
const LL mod = 1e9 + 7;
const double eps = 1e-9;
int pre[N];
LL dp[N];
struct node {
int w, b;
}people[N];
map<int,node>quan;
int n, m, w;
void init() {
for (int i = 0; i <= n; i++) {
pre[i] = i;
}
quan.clear();
memset(dp, 0, sizeof(dp));
}
int find(int x) {
if (pre[x] == x) {
return x;
}
return pre[x] = find(pre[x]);
}
void add(int a, int b) {
int aa = find(a);
int bb = find(b);
if (aa != bb) {
pre[aa] = bb;
}
}
bool cmp(node a, node b) {
if (a.w == b.w) {
return a.b > b.b;
}
return a.w < b.w;
}
int main() {
cin.sync_with_stdio(false);
int a, b;
while (cin >> n >> m >> w) {
init();
for (int i = 1; i <= n; i++) {
cin >> people[i].w;
}
for (int i = 1; i <= n; i++) {
cin >> people[i].b;
}
for (int i = 0; i < m; i++) {
cin >> a >> b;
add(a, b);
}
for (int i = 1; i <= n; i++) {
if (quan.find(find(i)) == quan.end()) {
quan[pre[i]].w = 0;
quan[pre[i]].b = 0;
}
quan[pre[i]].w += people[i].w;
quan[pre[i]].b += people[i].b;
}
for (map<int, node>::iterator it = quan.begin(); it != quan.end();it++) {
node now = it->second;
for (int i = w; i >= now.w; i--) {
dp[i] = max(dp[i], dp[i - now.w] + now.b);
}
}
cout << dp[w] << endl;
}
return 0;
}

1005 手机信号(签到题)

原题题目地址
我在打计蒜客的时候发现蛮有趣的题目,就出来水水了,没什么技巧,就是按照要求直接输出就好了

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#define N 310
#define inf 0x3f3f3f3f
using namespace std;
int main() {
int n;
cin.sync_with_stdio(false);
while (cin >> n) {
cout << "+-----+" << endl;
if (n < 20) {
cout << "| E|\n| |\n| |\n| |\n| |\n+-----+" << endl;
}
else if (n < 40) {
cout << "|- E|\n| |\n| |\n| |\n| |\n+-----+" << endl;
}
else if (n < 60) {
cout << "|- E|\n|-- |\n| |\n| |\n| |\n+-----+" << endl;
}
else if (n < 80) {
cout << "|- 3G|\n|-- |\n|--- |\n| |\n| |\n+-----+" << endl;
}
else if (n < 90) {
cout << "|- 3G|\n|-- |\n|--- |\n|---- |\n| |\n+-----+" << endl;
}
else if (n < 100) {
cout << "|- 4G|\n|-- |\n|--- |\n|---- |\n| |\n+-----+" << endl;
}
else {
cout << "|- 4G|\n|-- |\n|--- |\n|---- |\n|-----|\n+-----+" << endl;
}
}
return 0;
}

1006 涛神的城堡
这题也是从CF上得到的出题想法,原型题地址,我稍微改变了一点,你需要做一点处理才能得到原题的初始数据。原题题解
思路:就是一个前缀和的想法,先把涛涛对于每个人能得到多少钱或者失去多少钱预处理出来,然后通过前缀和就可以得到每个区间能的得到或者失去多少钱,moneysum[l~r]=sum[r]-sum[l-1]。然后做一个贪心操作,把能获得钱的区间取出来,要付钱的区间去掉,这样就是涛涛能获得的最大的钱数

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define LL long long
#define N 11000
#define M 50010
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const LL mod = 1e9 + 7;
const double eps = 1e-9;
int num[N];
int main() {
cin.sync_with_stdio(false);
int n, m;
int strong;
int a, b, c;
while (cin >> n >> m >> strong) {
num[0] = 0;
for (int i = 1; i <= n; i++) {
cin >> num[i];
num[i] = strong - num[i];
num[i] += num[i - 1];
}
int sum = 0;
for (int i = 0; i < m; i++) {
cin >> a >> b;
c = num[b] - num[a - 1];
if (c > 0) {
sum += c;
}
}
cout << sum << endl;
}
return 0;
}

1007 dada的GCD
思路:因为问你一个序列的任意区间的gcd是不是大于等于2,因为是任意区间,所有其实只有整个序列的gcd是大于等于2的时候任意区间的gcd是大于等于2的

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 100010
#define M 1000000
#define LL __int64
#define inf 0x3f3f3f3f
#define lson l,mid,ans<<1
#define rson mid+1,r,ans<<1|1
using namespace std;
const LL mod = 1e9 + 7;
const double eps = 1e-9;
LL num[N];
LL gcd(LL a, LL b) {
return b == 0 ? a : gcd(b, a%b);
}
int main() {
cin.sync_with_stdio(false);
int n, T;
cin >> T;
while (T--) {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> num[i];
}
if (n == 1) {
if (num[0] >= 2) {
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
}
else {
LL ans = gcd(num[0], num[1]);
for (int i = 2; i < n; i++) {
ans = gcd(ans, num[i]);
}
if (ans >= 2) {
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
}
}
return 0;
}

对比赛题解有任何疑问的可以在QQ上直接问我,或者私信我(~ ̄▽ ̄)~