文章目录
题目链接
PREV-1 核桃的数量
输出三者的最小公倍数即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
int main(){
ll a, b, c;
scanf("%lld %lld %lld", &a, &b, &c);
ll tem = a * b / __gcd(a, b);
ll ans = tem * c / __gcd(tem, c);
printf("%lld\n", ans);
return 0;
}
PREV-2 打印十字图
数据量小,暴力遍历,在周围加上一圈’.‘或者一圈’$’
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int INF = 0x3f3f3f3f;
char s[maxn][maxn];
bool near(int x, int y, char ch){
if(s[x - 1][y - 1] == ch || s[x - 1][y] == ch || s[x - 1][y + 1] == ch || s[x][y - 1] == ch || s[x][y + 1] == ch || s[x + 1][y - 1] == ch || s[x + 1][y] == ch || s[x + 1][y + 1] == ch){
return true;
}
return false;
}
int main(){
int n; scanf("%d", &n);
for(int i = 1; i <= 200; i++){
for(int j = 1; j <= 200; j++){
s[i][j] = '#';
}
}
int pos = 100;
s[pos][pos] = s[pos][pos - 1] = s[pos][pos - 2] = s[pos][pos + 1] = s[pos][pos + 2] = s[pos - 1][pos] = s[pos - 2][pos] = s[pos + 1][pos] = s[pos + 2][pos] = '$';
for(int t = 1; t <= 2 * n; t++){///&1 涂'.' 偶数涂'$'
if(t & 1){
for(int i = 1; i <= 200; i++){
for(int j = 1; j <= 200; j++){
if(s[i][j] != '#'){
continue;
}
if(near(i, j, '$')){
s[i][j] = '.';
}
}
}
}else{
for(int i = 1; i <= 200; i++){
for(int j = 1; j <= 200; j++){
if(s[i][j] != '#'){
continue;
}
if(near(i, j, '.')){
s[i][j] = '$';
}
}
}
}
}
for(int i = pos - 2 - n * 2; i <= pos + 2 + n * 2; i++){
for(int j = pos - 2 - n * 2; j <= pos + 2 + n * 2; j++){
if(s[i][j] == '#'){
printf(".");
}else{
printf("%c", s[i][j]);
}
}printf("\n");
}
return 0;
}
PREV-3 带分数
直接枚举所有的排列方式,1~9的全排列有2的9次方,1000个左右。
对于每个排列,枚举a b c三个数字的所有可能的位数,做一个分割验证。枚举a b c要1000不到,总的时间1e6
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int INF = 0x3f3f3f3f;
int a[100];
int n;
bool check(int x, int y, int z){
int i;
int aa = 0, b = 0, c = 0;
for(i = 1; i <= x; i++){
aa *= 10;
aa += a[i];
}
for(; i <= y; i++){
b *= 10;
b += a[i];
}
for(; i <= z; i++){
c *= 10;
c += a[i];
}
if(b % c != 0)
return false;
if(n == aa + b / c )
return true;
return false;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= 9; i++){///排列
a[i] = i;
}
int ans = 0;
do{
///对于每一个排列,都进行验证
for(int i = 1; i <= 7; i++){
for(int j = i + 1; j <= 8; j++){
int k = 9;
if(k - j >= 1){
if(check(i, j, k)){
ans++;
}
}
}
}
}while(next_permutation(a + 1, a + 1 + 9));
printf("%d\n", ans);
return 0;
}
PREV-4 剪格子
dfs搜索即可,以左上角作为起始搜索点,记录搜索到当前位置的连通块的大小,以及这些数字的和。
需要注意的是输入是先输入m再输入n(先列后行)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e2 + 10;
const int INF = 0x3f3f3f3f;
int G[maxn][maxn];
bool vis[maxn][maxn];
int n, m, tot;
int dx[] = {-1, 0, 0, 1};
int dy[] = {0, 1, -1, 0};
queue <pii> que;
int dfs(int x, int y, int sum, int sz){
//printf("%d %d\n", x, y);
vis[x][y] = true;
if(2 * sum == tot)
return sz;
if(2 * sum > tot)
return INF;
int mini = INF;
for(int i = 0; i < 4; i++){
int nxt_x = x + dx[i], nxt_y = y + dy[i];
if(nxt_x >= 1 && nxt_y >= 1 && nxt_x <= n && nxt_y <= m && !vis[nxt_x][nxt_y]){
mini = min(mini, dfs(nxt_x, nxt_y, sum + G[nxt_x][nxt_y], sz + 1));
vis[nxt_x][nxt_y] = false;
}
}
return mini;
}
int main(){
scanf("%d %d", &m, &n);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d", &G[i][j]);
tot += G[i][j];
}
}
if(tot & 1){
printf("0\n");
}else{
int ans = dfs(1, 1, G[1][1], 1);
printf("%d\n", ans);
}
return 0;
}
PREV-5 票据
读取数据,排序看一下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int INF = 0x3f3f3f3f;
int a[maxn];
char s[maxn];
int main(){
int n; scanf("%d", &n); getchar();
int cnt = 0;
for(int i = 1; i <= n; i++){
cin.getline(s, maxn);
int x = 0;
for(int j = 0; j < strlen(s); j++){
if(s[j] >= '0' && s[j] <= '9'){
x *= 10;
x += s[j] - '0';
}else{
if(x){
a[++cnt] = x;
}
x = 0;
}
if(j == strlen(s) - 1){
if(x)
a[++cnt] = x;
}
//printf("i:%d\n", i);
}
}
sort(a + 1, a + 1 + cnt);
for(int i = 2; i <= cnt; i++){
if(a[i] - a[i - 1] == 2){
printf("%d ", a[i] - 1);
}
}
for(int i = 2; i <= cnt; i++){
if(a[i] == a[i - 1]){
printf(" %d\n", a[i]);
}
}
return 0;
}
PREV-6 翻硬币
翻硬币游戏,从左往右贪心做即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
char s[maxn], ss[maxn];
void rev(char* p){
if(*p == '*')
*p = 'o';
else if(*p == 'o')
*p = '*';
}
int main(){
scanf("%s", s);
scanf("%s", ss);
int len = strlen(s);
int ans = 0;
for(int i = 0; i < len; i++){
if(s[i] != ss[i]){
ans++;
rev(s + i);
if(i + 1 < len)
rev(s + i + 1);
}
}
printf("%d\n", ans);
return 0;
}
PREV-7 连号区间数
n是5e4级别的,1s时限居然能用O(n^2)的方法做,这个评测机是战斗机吧。
其实是数据水了,数组开1e4的空间也能过。
直接枚举区间左右端点,判断当前区间是否是某个连续的,根据最大值减去最小值是否等于区间长度即可。(因为没有重复元素,可以这么算)
打正赛的时候要记得,不会做就暴力莽一发。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
int n;
int a[maxn];
void solve(){
ll ans = 0;
for(int i = 1; i <= n; i++){
int maxi = -1;
int mini= INF;
for(int j = i; j <= n; j++){
maxi = max(maxi, a[j]);
mini = min(mini, a[j]);
if(maxi - mini == j - i)
ans++;
}
}
printf("%lld\n", ans);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
}
solve();
return 0;
}
PREV-8 买不到的数目
暴力能过,直接枚举可达状态,取不可达的最大的,枚举到1e6即可。
直接求解是ab-a-b,可用找规律的方法找到。
也可证明ab-a-b是正解,具体见其他博客。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e8 + 10;
const int INF = 0x3f3f3f3f;
bool dp[maxn];
void solve(int x, int y){
dp[x] = dp[y] = true;
int pos;
for(int i = 0; i < 1e6; i++){
if(i - y > 0){
if(dp[i - y] || dp[i - x]){
dp[i] = true;
}else{
pos = i;
}
}
else if(i - x > 0){
if(dp[i - x]){
dp[i] = true;
}else{
pos = i;
}
}else{
pos = i;
}
}
printf("%d\n", pos);
}
int main(){
int n, m;
scanf("%d %d", &n, &m);
if(n > m)
swap(n, m);
solve(n, m);
return 0;
}
PREV-9 大臣的旅费
两次dfs跑出树的直径,然后因为花费是等差数列,直接根据式子算出答案即可。
要注意vis[1]在第一次dfs后要置为false。
或者dfs添加pre避免重复走。
发现数据很水
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e7 + 10;
const int INF = 0x3f3f3f3f;
struct Node{
ll v, c;
};
bool vis[maxn];
ll n, tot_dis = -1, tot_pos = -1;
vector <Node> G[maxn];
void dfs(ll u, ll dis){
vis[u] = true;
if(dis > tot_dis){
tot_dis = dis;
tot_pos = u;
}
for(ll i = 0; i < G[u].size(); i++){
ll v = G[u][i].v, c = G[u][i].c;
if(!vis[v]){
dfs(v, dis + c);
vis[v] = false;
}
}
return ;
}
int main(){
scanf("%lld", &n);
for(ll i = 1, x, y, z; i < n; i++){
scanf("%lld %lld %lld", &x, &y, &z);
G[x].push_back(Node{y, z});
G[y].push_back(Node{x, z});
}
///求树的直径
dfs(1ll, 0ll);
vis[1] = false;///****
tot_dis = -1ll;
dfs(tot_pos, 0ll);
printf("%lld\n", (21ll + tot_dis) * tot_dis / 2ll);
return 0;
}
/*
3
1 2 76
3 2 74
*/
PREV-10 幸运数
直接O(N^2)暴力筛掉即可AC
PREV-14 高僧斗法
nim博弈,看奇偶性,算异或即可。
从小到大枚举第一步操作,能让对方必败态则为该操作。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
int a[maxn];
int main(){
int n = 0;
char c;
while(1){
scanf("%d%c", &a[++n], &c);
if(c == '\n')
break;
}
int ans = 0;
for(int i = 2; i <= n; i += 2){
ans ^= a[i] - a[i - 1] - 1;
}
bool flag = false;
int k;
if(ans == 0)///必败态
printf("-1\n");
else{
for(int i = 1; i < n; i++){
for(int j = a[i]; j < a[i + 1]; j++){
k = a[i];
a[i] = j;
int ans = 0;
for(int x = 2; x <= n; x += 2){
ans ^= a[x] - a[x - 1] - 1;
}
if(ans == 0){///让对方成为必败态
flag = true;
printf("%d %d\n", k, j);
break;
}
a[i] = k;
}
if(flag){
break;
}
}
}
return 0;
}
PREV-21 回文数字
#include <bits/stdc++.h>
using namespace std;
int dit[10];
int n;
bool check(int x){
int cnt = 0, sum = 0;
while(x){
dit[++cnt] = x % 10;
sum += x % 10;
x /= 10;
}
int l = 1, r = cnt;
bool flag = true;
while(l < r){
if(dit[l] != dit[r]){
flag = false;
break;
}
l++;
r--;
}
if(sum != n)
flag = false;
return flag;
}
int main(){
scanf("%d", &n);
bool flag = false;
for(int i = 10000; i < 1000000; i++){
if(check(i)){
flag = true;
printf("%d\n", i);
}
}
if(!flag){
printf("-1\n");
}
return 0;
}
PREV-46 填字母游戏
这题很卡时间,很容易TLE。
要记忆化搜索,记忆化搜索博弈状态。
判断当前状态是否存在用mp.count(s) 别用 mp[s],不然也会T
#include <bits/stdc++.h>
using namespace std;
string s;
map <string, int> mp;
int solve(){
if(mp.count(s)){
return mp[s];
}
if(s.find("LOL") != -1){///找到LOL
return -1;
}
if(s.find("*") == -1){///没有空格,平局
return 0;
}
bool p = false;///平局标记
for(int i = 0; i < s.size(); i++){
if(s[i] == '*'){
s[i] = 'L';
int ret = solve();
s[i] = '*';
if(ret == -1){
return mp[s] = 1;
}else if(ret == 0){
p = true;
}
s[i] = 'O';
ret = solve();
s[i] = '*';
if(ret == -1){
return mp[s] = 1;
}else if(ret == 0){
p = true;
}
}
}
if(p)
return mp[s] = 0;
return -1;
}
int main(){
int t; scanf("%d", &t);
while(t--){
cin >> s;
printf("%d\n", solve());
}
return 0;
}