文章目录
试题A:美丽的2
题目
答案
563
思路
枚举
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
bool check(int n) {
while(n) {
int x = n % 10; // 取个位
if(x == 2) return true;
n /= 10; // 消除个位
}
return false;
}
signed main()
{
int ans = 0;
for(int i = 1 ; i <= 2020 ; i ++)
if(check(i)) ans ++ ;
cout << ans << endl;
return 0;
}
试题B:扩散
题目
答案
20312088
思路
bfs,污染格子
代码
/*
bfs
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 10005,P = 3000; //偏移量
int map[N][N];
struct Node{
int x,y;
int step;
};
const int dir[4][2] = {
{-1,0},{0,1},{1,0},{0,-1},
};
//相当于起始的时候队列中已经有了4个坐标
void bfs() {
queue<Node> que;
//初始坐标都+3000的偏移量
map[0+P][0+P] = 1;
map[2020+P][11+P] = 1;
map[11+P][14+P] = 1;
map[2000+P][2000+P] = 1;
que.push({0+P,0+P,0});
que.push({2020+P,11+P,0});
que.push({11+P,14+P,0});
que.push({2000+P,2000+P,0});
while(que.size()) {
Node cur = que.front();
que.pop();
if(cur.step == 2020) return;
//往四个方向扩散
for(int i = 0; i < 4; i++) {
int tx = cur.x + dir[i][0];
int ty = cur.y + dir[i][1];
int ts = cur.step + 1;
if(tx<0||tx>=N-5||ty<0||ty>=N-5) continue;
if(map[tx][ty]==1) continue;
map[tx][ty] = 1;
que.push({tx,ty,ts});
}
}
}
int main() {
cout << "开始了" << endl;
bfs();
cout << "输出了" << endl;
int ans = 0;
for(int i = 0; i < N-5; i++)
for(int j = 0; j < N-5; j++)
if(map[i][j]) ans++;
cout << ans << endl;
return 0;
}
试题C:阶乘约数
题目
答案
39001250856960000
思路
数论知识
基本算数定理
任何一个大于1的数,都可以表示成若干质数乘积的形式。(也就是分解质因数)
X = P 1 α 1 P 2 α 2 ⋯ P k α k X = P_1^{\alpha1}P_2^{\alpha2}\cdots P_k^{\alpha k} X=P1α1P2α2⋯Pkαk
约数个数定理
设约数个数为n
n = ( a 1 + 1 ) ( a 2 + 1 ) ⋯ ( a k + 1 ) n = (a_1+1)(a_2+1) \cdots (a_k+1) n=(a1+1)(a2+1)⋯(ak+1)
分解质因数模板
void divPrime(int n) {
for(int i = 2; i <= n/i; i++) {
if(n % i == 0) { //找到一个因子
//把它尽可能的除,直到不能整除
int s = 0; //次数
while(n % i == 0) {
n /= i;
s++;
}
cout << i << ' ' << s << endl;
}
}
//如果n还没除到1,那么就用n的1次方来做最后一个因子
if(n > 1) cout << n << ' ' << 1 << endl;
cout << endl; //输出空行
}
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 105;
int p[N];
void divPrime(int n) {
for(int i = 2; i <= n / i; i++) {
if(n % i == 0) {
while(n % i == 0) {
n /= i;
p[i] ++;
}
}
}
if(n > 1) p[n]++;
}
int main() {
int n = 100;
for(int i = 2; i <= 100; i++) divPrime(i);
long long ans = 1;
for(int i = 2; i <= n; i++)
if(p[i]) ans *= (p[i] + 1);
cout << ans << endl;
return 0;
}
试题D:本质上升序列
题目
答案
3616159
思路
DP,最长上升子序列的变种。
代码
/*
3616159
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 210;
int f[N]; //以a[i]结尾的上升序列的个数
int main() {
int n;
string a = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
n = a.size();
for(int i = 0; i < n; i++) {
for(int j = 0; j < i ;j++) {
if(a[j] < a[i])
f[i] += f[j];
else if(a[j] == a[i])
f[i] -= f[j]; //把算f[j]加过的,给去掉,所以减掉f[j]
}
f[i]++;
}
long long ans = 0;
for(int i = 0; i < n; i++) ans += f[i];
cout << ans << endl;
return 0;
}
以下代码的解释
if(a[j] == a[i])
f[i] -= f[j]; //把算前面相同的f[j]加过的,给去掉,所以减掉f[j]
举个例子
01234567
abczdefz
4和7是相同的z
012可以和3进行组合,所以f[3] = f[0] + f[1] + f[2]
012 456可以和7进行组合,所以f[7] = f[0] + f[1] + f[2] + f[4] + f[5] + f[6]
7需要减掉012这3个,因为他们和3组合,与和7组合的效果是一样的。
所以f[7] = f[7] - f[3]
这就做到了去重的目的
试题E:玩具蛇
问题
答案
552
思路
DFS枚举出所有可能的情况
代码
/*
dfs往里放(=1),可以放上下左右四个方向,得放法数量
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n = 4, m = 4;
const int dir[4][2] = {
{-1,0},{0,1},{1,0},{0,-1},
};
int a[6][6]; //4*4
int cnt,ans; //cnt放了几个
void dfs(int x,int y,int cnt) {
if(cnt==16) {
ans++;
return;
}
for(int i = 0; i < 4; i++) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx<1||tx>n||ty<1||ty>m) continue;
if(a[tx][ty]==1) continue;
a[tx][ty] = 1;
dfs(tx,ty,cnt+1);
a[tx][ty] = 0;
}
}
int main() {
//遍历每种起点
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 4; j++) {
a[i][j] = 1;
dfs(i,j,1);
a[i][j] = 0; //回溯
}
}
cout << ans << endl;
return 0;
}
试题F:皮亚诺曲线距离
不会
试题G:游园安排
题目
题目简化
思路
分割,最长上升子序列,输出路径。评测系统过不了全部样例,不知道为什么。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <unordered_map>
using namespace std;
const int N = 100010;
string a;
string b[N];
string q[N]; //q[i]表示长度为i的最小的字符串
unordered_map<string,string> s; //s[k]表示k的上一个字符串,用于回溯路径
string fk; //最后一个字符串
//WoAiLanQiaoBei
int main() {
cin >> a;
//分割字符串
int k = -1;
for(auto c : a) {
if(c >= 'A' && c <= 'Z') k++;
b[k] += c;
}
int n = k + 1; //b的个数
//求最长公共子序列(贪心+二分法)
int len = 0;
q[0] = "";
for(int i = 0 ; i < n; i++) {
//在q[0,len]中找比b[i]小的字符串中最大的长度
int l = 0, r = len;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (q[mid].compare(b[i]) < 0) l = mid;
else r = mid - 1;
}
s[b[i]] = q[r]; //b[i]的上一个字符串是q[r]
if(r + 1 > len) {
len = r + 1;
fk = b[i]; //最后一个字符串是b[i]
}
q[r + 1] = b[i];
}
//cout << len << endl;
//从最后一个字符串开始,不断溯源,送进vector
vector<string> t;
for(int i = 0; i < len; i++) {
t.push_back(fk);
fk = s[fk];
}
//使其正向输出
for(int i = t.size() - 1; i >= 0; i--)
cout << t[i];
cout << endl;
return 0;
}
试题H:答疑
题目
思路
贪心,优先考虑总时间小的同学,其次考虑e小的同学。
计算式子如下
ans = (s0+a0) + (s0+a0+e0+s1+a1) + (s0+a0+e0+s1+a1+e1+s2+a2)...
想想是优先考虑总时间还是s+a。
如果A同学s+a=10,e=20,sum=30,B同学s+a=20,e=5,sum=25。
优先考虑总时间小的,序列为BA,结果为25 + 10 = 35
优先考虑s+a小的,序列为AB,结果为30 + 20= 50
所以要优先考虑总时间小的。
想想sum相等的情况下,要考虑s+a还是e
如果A同学s+a=10,e=20,sum=30,B同学s+a=20,e=10,sum=30。
优先考虑e小的,序列为BA,结果为20+10+10 = 40
优先考虑s+a小的,序列为AB,结果为10+20+20= 50
所以sum相等的情况下,要考虑e小的。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1005;
int n;
struct Stu{
int s,a,e,sum; //sum是三个的和
//把总和小的排在前面,其次考虑e小的
bool operator< (const Stu &t) const{
if(sum != t.sum) return sum < t.sum;
else return e < t.e;
}
} stu[N];
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", &stu[i].s, &stu[i].a, &stu[i].e);
stu[i].sum = stu[i].s + stu[i].a + stu[i].e;
}
//根据规则排序
sort(stu + 1, stu + n + 1);
//加时刻和答案
LL time = 0, ans = 0;
for(int i = 1; i <= n; i++) {
time += stu[i].s + stu[i].a;
ans += time;
time += stu[i].e;
}
cout << ans << endl;
return 0;
}
试题I:出租车
不会
试题J:质数行者
题目
思路
DFS暴搜,骗到分就算胜利
代码
/*
5 6 1
3 4 1 1 2 1
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1005, MOD = 1e9+7;
int n, m, w; //n行m列w层
int r1,c1,h1,r2,c2,h2; //陷阱位置
long long ans;
//向东走,向南走,向上走
const int dir[3][3] = {
{0,1,0},{1,0,0},{0,0,1},
};
//判别质数
bool isPrime(int x) {
if(x < 2) return false;
for(int i = 2; i <= x / i; i++)
if(x % i == 0) return false;
return true;
}
void dfs(int x, int y, int z) {
if(x == n && y == m && z == w) {
ans = (ans + 1) % 1000000007;
return;
}
//往3个方向走
for(int i = 0; i < 3; i++) {
//尝试不同的质数
for(int j = 2; j <= n || j <= m || j <= w; j++) {
if(!isPrime(j)) continue;
int tx = x + j * dir[i][0];
if(tx > n) continue;
int ty = y + j * dir[i][1];
if(ty > m) continue;
int tz = z + j * dir[i][2];
if(tz > w) continue;
//刚好在陷阱上,不算
if(tx == r1 && ty == c1 && tz == h1) continue;
if(tx == r2 && ty == c2 && tz == h2) continue;
dfs(tx, ty, tz);
}
}
}
int main() {
cin >> n >> m >> w;
cin >> r1 >> c1 >> h1;
cin >> r2 >> c2 >> h2;
dfs(1,1,1); //从111走到nmw
cout << ans << endl;
return 0;
}
输出路径
/*
5 6 1
3 4 1 1 2 1
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1005, MOD = 1e9+7;
int n, m, w; //n行m列w层
int r1,c1,h1,r2,c2,h2; //陷阱位置
long long ans;
struct Node{
int x, y, z;
};
vector<Node> vis;
//向东走,向南走,向上走
const int dir[3][3] = {
{0,1,0},{1,0,0},{0,0,1},
};
//判别质数
bool isPrime(int x) {
if(x < 2) return false;
for(int i = 2; i <= x / i; i++)
if(x % i == 0) return false;
return true;
}
void dfs(int x, int y, int z) {
if(x == n && y == m && z == w) {
for(auto t : vis) {
printf("(%d,%d,%d)",t.x,t.y,t.z);
if( !(t.x == n && t.y == m && t.z == w) ) cout << '-';
}
cout << endl;
ans = (ans + 1) % 1000000007;
return;
}
//往3个方向走
for(int i = 0; i < 3; i++) {
//尝试不同的质数
for(int j = 2; j <= n || j <= m || j <= w; j++) {
if(!isPrime(j)) continue;
int tx = x + j * dir[i][0];
if(tx > n) continue;
int ty = y + j * dir[i][1];
if(ty > m) continue;
int tz = z + j * dir[i][2];
if(tz > w) continue;
//刚好在陷阱上,不算
if(tx == r1 && ty == c1 && tz == h1) continue;
if(tx == r2 && ty == c2 && tz == h2) continue;
vis.push_back({tx,ty,tz});
dfs(tx, ty, tz);
vis.pop_back();
}
}
}
int main() {
cin >> n >> m >> w;
cin >> r1 >> c1 >> h1;
cin >> r2 >> c2 >> h2;
vis.push_back({1,1,1});
dfs(1,1,1); //从111走到nmw
cout << ans << endl;
return 0;
}