题目链接:abc190
A - Very Very Primitive Game
题目大意
- Takahashi 和 Aoki吃糖果,轮流吃糖果,如果轮到的人没糖果了那么就输。
- a是T拥有的糖果数,b是A拥有的糖果数,c=0说明T先吃,c=1说明A先吃。
- 输出赢家
- 0≤A,B≤100
思路
- A先吃说明T已经吃完一颗了,所以可以让a+c,那么就统一T先吃糖果了
- 如果a>b则T赢,否则A赢
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int a, b, c;
cin >> a >> b >> c;
a += c;
if(a > b) puts("Takahashi");
else puts("Aoki");
return 0;
}
B - Magic 3
题目大意
- 魔术师打怪,n种咒语,每种咒语持续时间是ai,伤害是bi
- 怪物能够承受最短时间是s,最大伤害是d
- 问魔术师能够成功击杀怪物
- 范围1≤N≤100, 1≤ai≤1e9, 1≤bi≤1e9, 1≤s≤1e9, 1≤d≤1e9
思路
- 找所有咒语中是否有ai<s并且bi>d即可
- 这里用了与运算
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int n, s, d, flag = 0;
scanf("%d%d%d", &n, &s, &d);
while(n --){
int x, y;
scanf("%d%d", &x, &y);
flag |= (x < s && y > d);
}
if(flag) puts("Yes");
else puts("No");
return 0;
}
C - Bowls and Dishes
题目大意
- 有n种菜,m种搭配a1, bi,k个人选菜,
- 每个人都有两种选择ci ,di,选完之后看满足多少种搭配
- 问最多满足多少搭配
- 范围:2≤N≤100,1≤M≤100,1≤Ai<Bi≤N,1≤K≤16, 1≤Ci<Di≤N
思路
- 状态压缩
- 因为最多只有16个人,那么可以二进制枚举所有情况,0表示选第一个菜,1表示选择第二个菜,并标记vis数组
- 然后遍历搭配,如果两者都存在,则cnt++,最后更新这个cnt最大值即可
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int a[105], b[105], c[105], d[105];
int vis[105];
int main(){
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++){
scanf("%d%d", &a[i], &b[i]);
}
int k; scanf("%d", &k);
for(int i = 0; i < k; i ++){
scanf("%d%d", &c[i], &d[i]);
}
int ans = 0;
for(int t = 0; t < (1 << k); t ++){
for(int i = 1; i <= n; i ++) vis[i] = 0;
for(int i = 0; i < k; i ++){
if((t >> i) & 1) vis[d[i]] = 1;
else vis[c[i]] = 1;
}
int cnt = 0;
for(int i = 1; i <= m; i ++){
if(vis[a[i]] + vis[b[i]] == 2) cnt ++;
}
ans = max(ans, cnt);
}
printf("%d\n", ans);
return 0;
}
D - Staircase Sequences
题目大意
- 给你一个n,问你能构成几个等差数列,公差d是1,数列的和是n?
- 1≤N≤1e12
思路
- 等差数列的求和公式是S=n*a0+n*(n-1)*d/2
- d=1,那么S就与项数n和首项a0有关了,S已知,那么就用n表示a0: a0=S/n-(n-1)/2 -> 2a0=2S/n+1-n
- a0是整数,所以需要满足2S/n+1-n是偶数,并且n是2S的因子。
- 跑O()时间求出满足条件的n的个数即可。
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
ll n; cin >> n;
int cnt = 0;
n <<= 1;
for(int i = 1; i <= sqrt(n); i ++){
if(n % i == 0){
if((n / i + 1 - i) % 2 == 0) cnt ++;
ll d = n / i;
if(i == d) continue;
if((n / d + 1 - d) % 2 == 0) cnt ++;
}
}
cout << cnt << endl;
return 0;
}
F - Shift and Inversions
题目大意
- 给你n个0到n-1全排列的数组,然后这个数组会循环左移n-1
- 问你这个过程中数组的逆序数对是多少
- 逆序数对,满足i<j, ai>aj 的对<i,j>的个数
- 2≤N≤3×1e5
思路
- 初始的逆序对ans用树状数组或者归并排序做,这里就用树状数组的了,
- 然后比如{2, 0, 1, 3}这个对循环左移变成了{0, 1, 3, 2},就是2往后移了,那么现在,比2小的数移到了左边,逆序对就少了a1对,比2大的数也移到了左边,逆序对就多了a2对
- 由于他是全排列,那么比2小的数a1就有2对,比2大的数a2就有4 - 1 - 2对,也就是说只需要ans - a1 + a2就行了。
- 逆序对最大值是n*(n - 1) / 2所以会爆int,需要开long long
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) x & -x
const int maxn = 3e5 + 5;
int c[maxn], n;
void add(int x){
for(int i = x; i <= n; i += lowbit(i))
c[i] ++;
}
int query(int x){
int ans = 0;
for(int i = x; i > 0; i -= lowbit(i))
ans += c[i];
return ans;
}
int a[maxn];
int main(){
ll ans = 0; cin >> n;
for(int i = 1; i <= n; i ++){
cin >> a[i]; a[i] ++;
//由于树状数组不能加0,所以a[i]需要加1,那么下面的d1就要对应的+1, d2要对应的-1
add(a[i]);
//query求的是小于等于a[i]的数的个数,i是现在有的个数
//那么现在要求的是逆序对,也就是要求前面比他大的数的个数,那么就是i-query
ans += i - query(a[i]);
}
int d1 = 0, d2 = 0;
for(int i = 1; i <= n; i ++){
cout << ans << endl;
d1 = n - a[i], d2 = a[i] - 1;
ans += d1 - d2;
}
return 0;
}