- 简单
- C
- E
- F
- 中等
- B 博弈论、栈
- E 贪心
- 困难
- A 模拟+优先队列(小根堆)
- D dfs
A Heap Operations CodeForces - 681C
题意
有个堆,有三种操作
- insert x — 把x加到堆里。
- getMin x — 得到堆里的最小值,且最小值等于x,当堆为空或者最小值不等于x时操作违法。
- removeMin — 删除堆里的最小值,当堆为空时操作违法。
题目给出了一些操作,不一定合法,往里再添加一些操作使得所有的操作都合法,求添加操作最少的情况并按序输出全部操作(新添加的和已存在的)。
题解
优先队列模拟操作
- 当前操作为insert x时向队列中加入x
- 当前操作为removeMin时将队列的top()删除,若队列为空则在removeMin前先insert一个在x的定义域内的任意值就好了
- 当前操作为getMin x时:
- 如果队列为空,则先insert x
- 如果队列不为空,removeMin 掉所有比x小的,在此之后若top()大于x或队列为空,则insert x
AC代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
#include<ctime>
#include<string>
#include<vector>
#include<map>
#include<list>
#include<set>
#include<stack>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pii;
typedef pair<ll, ll> pll;
const ll N = 2e5 + 5;
const ll mod = 2017;
const ll INF = 0x3f3f3f3f;
const ll INF64 = 0x3f3f3f3f3f3f3f3f;
const double gold = (1 + sqrt(5)) / 2.0;
const double PI = acos(-1);
const double eps = 1e-8;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll pow(ll x, ll y, ll mod) { ll ans = 1; while (y) { if (y & 1)ans = (ans * x) % mod; x = (x * x) % mod; y >>= 1; }return ans; }
ll pow(ll x, ll y) { ll ans = 1; while (y) { if (y & 1)ans = (ans * x) % mod; x = (x * x) % mod; y >>= 1; }return ans; }
ll inv(ll x) { return pow(x, mod - 2); }
priority_queue<int,vector<int> ,greater<int> >pq;
char com[100005][10];
int s[100005];
string p;
int main() {
int n,m;
scanf("%d", &n);
m = n;
for (int i = 0; i < n; i++) {
scanf("%s", com[i]);
if (com[i][0] != 'r')
scanf("%d", &s[i]);
}
for (int i = 0; i < n; i++) {
if (com[i][0] == 'i') {
pq.push(s[i]);
}
else if (com[i][0] == 'r') {
if (pq.empty()) {
p += "insert 0\n";
m++;
}
else {
pq.pop();
}
}
else {
while (pq.size() && pq.top() < s[i]) {
p+="removeMin\n";
m++;
pq.pop();
}
if (pq.empty() || pq.top() != s[i]) {
p+="insert "+to_string(s[i])+'\n';
m++;
pq.push(s[i]);
}
}
p += com[i];
p+=' ';
if (com[i][0] != 'r')p += to_string(s[i]);
p += '\n';
}
cout<< m <<'\n'<< p;
return 0;
}
B Game with string CodeForces - 1104B
题意
题意:
两个人正在围绕着一个仅有小写字母组成的字符串 s玩一个游戏
在一个玩家的回合, 他必须选择字符串中的两个相邻并且相同字母删除。
例如, 如果当前字符串是 “xaax” 那么就只有一种可能,删除 “aa”, 所以字符串将变为 “xx”。两个人都想赢。
现在需要你求出最后谁会赢如果两人都选择最优策略。
题解
容易知道删除字符的顺序不影响总删除次数,所以实际上对于一个特定的字符串,删除次数是固定不变的,因此我们只要求出总次数然后判断奇偶性就好,判断使用栈判断,其他方法也行,栈比较方便。
AC代码
char s[100005];
char st[100005];
int main(){
int n,k=0,ans=0;
scanf("%s",s);
for(int i=0;s[i];i++){
if(k==0){
st[k++]=s[i];
}
else{
if(st[k-1]==s[i]){
k--;
ans++;
}
else {
st[k++]=s[i];
}
}
}
printf("%s\n",ans%2?"Yes":"No");
return 0;
}
C Splitting into digits CodeForces - 1104A
题意
将给定数拆分成多个数的组合,使种类尽量少。
题解
数据很小全部拆成1就好
AC代码
int main(){
int n;
scanf("%d",&n);
printf("%d\n",n);
for(int i = 0; i < n; i++){
printf("1 ");
}
printf("\n");
return 0;
}
D Sudoku POJ - 2676
题意
九宫格问题,也叫数独问题。把一个9行9列的网格,再细分为9个3*3的子网格,要求每行、每列、每个子网格内都只能使用一次1~9中的一个数字,即每行、每列、每个子网格内都不允许出现相同的数字。0是待填位置,其他均为已填入的数字。要求填完九宫格并输出(如果有多种结果,则只需输出其中一种)。如果给定的九宫格无法按要求填出来,则输出原来所输入的未填的九宫格。
题解
经典dfs问题,直接搜索容易超时,要一定程度的优化,使用bh[i][x]判断第i行的x有无出现过;使用bl[i][x]判断第i列的x有无出现过;使用bk[i][x]判断第i块的x有无出现过。
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
int n = 0;
int f[11][11];
int bh[11][11], bl[11][11], bk[11][11];
int flag;
struct point {
int x, y;
};
point l[82];
int judge(int x, int y) {
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
if (x <= 3 * i&&y <= 3 * j)
return (i - 1) * 3 + j;
}
void dfs(int num) {
if (flag)return;
if (num == n) {
printf("\n");
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++)
printf("%d", f[i][j]);
printf("\n");
}
flag = 1;
return;
}
int x = l[num].x, y = l[num].y;
int k = judge(l[num].x, l[num].y);
for (int i = 1; i <= 9; i++) {
if (!bh[x][i] && !bl[y][i])
if (!bk[k][i]) {
bh[x][i] = bl[y][i] = bk[k][i] = 1;
f[x][y] = i;
dfs(num + 1);
bh[x][i] = bl[y][i] = bk[k][i] = 0;
f[x][y] = 0;
}
}
}
int main() {
int t;
cin >> t;
while (t--) {
flag = 0;
n = 0;
for (int i = 1; i <= 9; i++)
for (int j = 1; j <= 9; j++) {
scanf("%1d", &f[i][j]);
if (f[i][j] == 0)l[n++] = { i,j };
else {
bh[i][f[i][j]] = 1;
bl[j][f[i][j]] = 1;
bk[judge(i, j)][f[i][j]] = 1;
}
}
dfs(0);
for (int i = 0; i < 11; i++)
for (int j = 0; j < 11; j++) {
f[i][j] = 0;
bl[i][j] = 0;
bh[i][j] = 0;
bk[i][j] = 0;
}
for (int i = 0; i < 82; i++) {
l[i].x = 0;
l[i].y = 0;
}
}
return 0;
}
E 均分纸牌 计蒜客 - T2158
题意
均分纸牌
题解
经典贪心问题,求出平均数也就是最终状态,然后递推一遍算次数就好。
AC代码
int s[102];
int main() {
int n,sum=0,ans=0;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", s + i);
sum += s[i];
}
sum /= n;
for (int i = 0; i < n; i++) {
if(i)s[i] += s[i - 1] - sum;
ans += (s[i] - sum) ? 1 : 0;
}
printf("%d\n", ans);
return 0;
}
F Space Navigation CodeForces - 1481A
题意
从给定的操作中选择一些,问你能否达到终点。
题解
统计下各种操作个数,然后比较下大小就好。
AC代码
char s[N];
int main() {
int t,px,py;
scanf("%d", &t);
while (t--) {
int u, d, l, r;
u = d = l = r = 0;
scanf("%d%d%s", &px, &py, s);
for (int i = 0; s[i]; i++) {
if (s[i] == 'U')u++;
else if (s[i] == 'D')d++;
else if (s[i] == 'L')l++;
else if (s[i] == 'R')r++;
}
if (py <= u && py >= -d && px <= r && px >= -l)
printf("YES\n");
else printf("NO\n");
}
return 0;
}
G Mishka and Contest CodeForces - 999A
题意
给出 n 个问题的难度以及可以解决问题的能力 k,每次只能从问题列表的左边或右边解决问题,如果问题难度高于 k,其后或其前的问题就无法解决,求最多可以解决多少问题。
题解
分别从右向左、从左向右枚举,注意如果 k 大于所有问题的难度,即解决的问题数为2倍的给出问题数,直接输出问题数即可。
AC代码
nt s[105];
int main() {
int n, k;
scanf("%d%d",&n,&k);
for (int i = 0; i < n; i++)
scanf("%d", s + i);
int ans = 0;
for (int i = 0; i < n; i++) {
if (s[i] > k) {
break;
}
ans++;
}
for (int i = n-1; i>=0; i--) {
if (s[i] > k) {
break;
}
ans++;
}
if (ans > n)ans /= 2;
printf("%d\n", ans);
return 0;
}