题目解析(暂时还有CDFI没补)
A - The vowel is the best letters
B - The treasure you find is the best treasure
C - The biggest number is the best number
D - The longest string is the best string
E - The most regular graphics is the best graphic
F - The most suitable structure is the best structure
G - The smallest move is the best move
H - The smartest candidates is the best candidate
I - The most capable man is the best man
J - The highest mountain is the best mountain
K - The fullest bag is the best bag
L - The question from Carl are the best questions
A - The vowel is the best letters(构造+规律)
题目大意:给定一个只包含小写阿拉伯字母的字符串,问通过构造可以构造出几种方式。
构造方式:
一、对于元音‘a','e','i','o','u',将其加入到最后一位,并将整个字符串反转
二、对于其他字母,加入到最后一位
思考方式以及情况判断:
思考方式:按有1 2 3位元音模拟
情况判断:
1.当没有元音时只有一种方式
2.当有元音且只有一个时,该元音必然在开头,样例如ca是不合理的,会反转变成ac
3.当元音超过一个时,必须要有一个元音在开头。
根据样例acmicpc得出三种情况分别为
imcacpc
micacpc
cmiacpc
扩展到三位可知道如acmicec
icemcac
ciemcac
多位以后也会根据此变换方式改变变换方式,使得中间偏后的两位换到最前面,而前面可以在此之间自由变换位置。见acmicpc中i的位置。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
string str;
bool check(char s)
{
if(s == 'a' || s == 'e'|| s == 'i' || s == 'o' || s == 'u') return true;
return false;
}
void solve()
{
vector<int>v;
cin >> str;
for(int i = 0; i < str.size(); i ++)
if(check(str[i]))
v.push_back(i);
int cnt = v.size();
//cout << v.size() << endl;
bool st = check(str[0]);
if(!cnt)
{
puts("1");
return;
}
if(cnt && !st)
{
puts("0");
return;
}
if(cnt == 1 && st)
{
cout << str.size() << '\n';
return;
}
if(cnt > 1 && st)
{
if(cnt & 1) cout << v[cnt / 2 + 1] - v[cnt / 2] << '\n';
else cout << v[cnt / 2] - v[cnt / 2 - 1] << '\n';
}
}
int main()
{
solve();
system("pause");
return 0;
}
B - The treasure you find is the best treasure(长得像数位dp的dfs)
真nm简单!注意要点:边走边取模解决大数整除问题,同位剪枝
题目大意:给定有位置上数字未知的高精度整数,找到满足整除并且没有前导0的的最小数
暴力遍历每一位情况即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 1010;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
string str;
int n;
bool st = false;
int ans[N];
bool b[N][N];
void dfs(int pos,int div)
{
if(pos == str.size())
{
if(!div) st = true;
return;
}
if(str[pos] >= '0' && str[pos] <= '9')
{
ans[pos] = str[pos] - '0';
b[pos][(div * 10 + ans[pos]) % n] = true;
dfs(pos + 1,(div * 10 + ans[pos]) % n);
}
else
{
for(int i = 0; i <= 9; i ++)
{
if(pos == 0 && i == 0) continue;
if(!b[pos][(div * 10 + i) % n])
{
ans[pos] = i;
b[pos][(div * 10 + i) % n] = true;
dfs(pos + 1,(div * 10 + i) % n);
}
if(st) break;
}
}
return;
}
void solve()
{
cin >> str;
cin >> n;
dfs(0,0);
if(st)
{
for(int i = 0;i < str.size(); i ++)
putchar('0' + ans[i]);
puts("");
}
else puts("*");
return;
}
int main()
{
solve();
system("pause");
return 0;
}
C - The biggest number is the best number(lca)
D - The longest string is the best string(trie+ac自动机)
E - The most regular graphics is the best graphic(几何)
题目大意:.是白的#是黑的求至少(长度大于1的算一条)有多少条边
思路:点在四个的块中为3或1算一条边
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 110;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
char s[N][N];
bool check(int x,int y)
{
//if(st[x][y]) return false;
int sum = (s[x][y] == '.') + (s[x - 1][y - 1] == '.') + (s[x - 1][y] == '.') + (s[x][y - 1] == '.');
if(sum == 3 || sum == 1) return true;
else return false;
}void solve()
{
int ans = 0;
int n,m;
cin >> n >> m;
for(int i = 0; i < n; i ++) cin >> s[i];
for(int i = 1; i < n; i ++)
{
for(int j = 1; j < m;j ++)
{
if(check(i,j)) ans ++;
}
}
cout << ans << '\n';
}
int main()
{
solve();
system("pause");
return 0;
}
F - The most suitable structure is the best structure(势能线段树)
G - The smallest move is the best move(思维)
https://zhuanlan.zhihu.com/p/268630329
题目大意:给定n个有序对<ai,bi>,作为机器人的位置,m个有序对<ai,bi>作为灯的位置,考虑通过对所有盗贼向右移动(A)或向上移动(B),使得所有盗贼能出去的的最小值
题目思路:对于在灯内的盗贼,可以直上或直下或者拐弯,可以通过遍历一个方向,从而找出令一个方向满足恰好出去(最大值)的最小值。
题目解法:存出在灯内,走过ci - ai 的并能出去的最大值y,那么对于任何一个>=x都成立,寻找最小值
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
int a[N],b[N],c[N],d[N];
int cnt[N];
void solve()
{
int n,m;
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i] >> b[i];
for(int j = 1; j <= m; j ++) cin >> c[j] >> d[j];
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
{
if(a[i] <= c[j] && b[i] <= d[j])
{
cnt[c[j] - a[i]] = max(cnt[c[j] - a[i]],d[j] - b[i] + 1);
}
}
int maxn = 0;
int ans = INF;
for(int i = N; i >= 0; i --)
{
maxn = max(maxn,cnt[i]);//向上最多
//cout << maxn << endl;
ans = min(ans,i + maxn);
}
cout << ans << endl;
}
int main()
{
solve();
system("pause");
return 0;
}
H - The smartest candidates is the best candidate(思维+贪心)
题目大意:祖安竞选,如果范德尔去一个城市宣讲,那么原来支持希尔科和范德尔的都支持范德尔,如果不去,原本支持范德尔的那些人就会放弃选举,原本支持希尔科的人会继续支持希尔科。问至少参加几次竞选可以让范德尔稳赢
假设原本支持范德尔的总和是sumb,原本支持希尔科的总和是suma,支持范德尔的是bi,希尔科的是ai;
对于去的城市,范德尔:sumb + a 希尔科:suma - a
对于不去的城市:范德尔:sumb - b 希尔科:suma
因此对于范德尔去和不去的总考虑值就是sumb + a - (sumb - b) = a + b
因此对于希尔科去和不去的总考虑值就是suma - a - suma = -a
根据峡谷相对论,我吃对面一组F6,相当于我赢一组F6,对面输一组F6,我赢两波!因此对面输a实际上我得利2a,总考虑值2a+b,贪心排序即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
struct node
{
ll x,y;
bool operator < (const node w) const
{
return 2 * w.x + w.y < 2 * x + y;
}
}a[N];
void solve()
{
int n;
scanf("%d",&n);
ll suma = 0,sumb = 0;
for(int i = 0; i < n; i ++)
{
ll x,y;
scanf("%lld%lld",&x,&y);
a[i] = {x,y};
suma += x;
}
sort(a,a + n);
// for(int i = 0; i < n; i ++)
// {
// cout << a[i].x << " " << a[i].y << endl;
// }
for(int i = 0; i < n; i ++)
{
sumb += a[i].x + a[i].y;
suma -= a[i].x;
if(sumb > suma)
{
cout << i + 1 << '\n';
return;
}
}
}
int main()
{
solve();
system("pause");
return 0;
}
I - The most capable man is the best man(思维)
J - The highest mountain is the best mountain(思维签到)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 310;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
int a[N][N];
int d[6];
void solve()
{
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
scanf("%d",&a[i][j]);
int ans = -1;
for(int i = 2; i <= n; i ++)//遍历边长有几个点的正方形,边长为i - 1
{
for(int len = 1; len + i - 1 <= n; len ++)//遍历左上角的点的横坐标
{
for(int j = 1; j + i - 1 <= n;j ++)//遍历左上角的纵坐标
{
d[0] = a[len][j];//左上
d[1] = a[len + i - 1][j];//左下
d[2] = a[len][j + i - 1];//右上
d[3] = a[len + i - 1][j + i - 1];//右下
sort(d,d + 4);
if(d[0] == d[2] && d[3] > d[2]) ans = max(ans,d[0]);
}
}
}
printf("%d\n",ans);
}
int main()
{
solve();
system("pause");
return 0;
}
K - The fullest bag is the best bag(思维+优先队列实现)
题目大意:n体积的背包,m个物品,物品的体积都是2的倍数,并且每个物品可以等分成两份。问填满背包的最大分次数,如果填不满就是-1
思考方式以及情况判断:
思考方式:题目1 <= n <= 1e18 过大没法直接使用背包dp(如果有我太菜惹不知道QAQ)
考虑贪心。
情况判断:
只有当总和加起来也填不满才会出现-1,其他时候都会有解。
贪心的去把他从大到小的放。粗略证明:如果先放小的,对于大的不能放需要砍大的,不能用小的凑,
例子:
33 4
1 2 4 32
显然答案是0,然而如果我从小往大放的话,需要砍32,必然不是最优解,从而考虑:
(1)用优先队列贪心 --- 每次切两半的数保证次序
(2)从大到小放:
1、如果能放,则把他放进去
2、如果不能放,并且还装不满,把他砍成两半
3、如果不能放进去,还能装满,直接扔掉就好惹
#include<bits/stdc++.h> using namespace std; #define ll long long #define PII pair<int, int> #define PLL pair<ll, ll> const int N = 1e6 + 10; const int M = 2 * N; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; const double PI = acos(-1.0); const double eps = 1e-8; void solve() { ll n,m,sum = 0; cin >> n >> m; priority_queue<int>heap; for(int i = 0; i < m; i ++) { int x; cin >> x; heap.push(x); sum += x; } if(sum < n) { puts("-1"); return; } //这里的sum实际上是总的集合 ll ans = 0; while(n) { auto t = heap.top(); heap.pop(); if(n >= t)//能放进去 { n -= t; sum -= t; } else if(n > sum - t)//放不进去了,并且如果不放他就放不满 { heap.push(t >> 1); heap.push(t >> 1); ans ++; } else sum -= t; //处理集合给他扔掉 } cout << ans << endl; } int main() { int t; cin >> t; while(t --) solve(); system("pause"); return 0; }
PS:下边是从小到大的方式,不做过多解释(xyggyyds)
#include <bits/stdc++.h> using namespace std; #define ll long long #define PII pair<int, int> #define PLL pair<ll, ll> const int N = 1e6 + 10; const int M = 2 * N; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; const double PI = acos(-1.0); const double eps = 1e-8; void solve() { ll n, m; cin >> n >> m; vector<int> f(62); ll sum = 0; for (int i = 1; i <= m; i++) { int x; cin >> x; sum += x; for (int j = 0; j <= 31; j++) { if ((1ll << j) & x) f[j]++; } } //cout << sum << endl; if (sum < n) { puts("-1"); return; } int ans = 0; for (int i = 0; i <= 60; i++) { if ((1ll << i) & n) { if (f[i]) f[i]--; else { int j = i + 1; for (j; j <= 60; j++) if (f[j]) break; for (j; j > i; j--) f[j]--, f[j - 1] += 2, ans++; f[i]--; } } f[i + 1] += f[i] / 2; } cout << ans << endl; } int main() { int t; cin >> t; while(t --) solve(); system("pause"); return 0; }
L - The question from Carl are the best questions(思维签到)
题目大意:
gcd(a,b) == gcd(c,d)
min(c,d) > max(a,b)
给定1<= a,b<= 1e9 求1<=c,d<=1e15
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
void solve()
{
ll a,b;
scanf("%lld%lld",&a,&b);
int t = __gcd(a,b);//找到最大公因数
int maxn = max(a,b);//找到最大数
int qwq = maxn / t;//找到和最大公因数差多少倍
printf("%lld %lld\n",(qwq + 1) * t,(qwq + 2) * t);
}
int main()
{
int t;
cin >> t;
while(t --)
solve();
system("pause");
return 0;
}