div2 唯唯诺诺 div3 重拳出击
A
除完3 分类讨论即可
int main() {
int t;
cin >> t;
while (t --) {
int n;
cin >> n;
int base = n / 3;
int a, b, c;
if (n % 3 == 0) a = base + 1, b = base, c = base - 1;
if (n % 3 == 1) a = base + 2, b = base, c = base - 1;
if (n % 3 == 2) a = base + 2, b = base + 1, c = base - 1;
cout << b << " " << a << " " << c << endl;
}
return 0;
}
B
取一下两个数组的最大差 看一看其他的是不是满足
int main() {
int t;
cin >> t;
while (t --) {
int n;
cin >> n;
vector a(n, 0), b(n, 0);
int f = 1, dis = 0;
for(int i = 0; i < n; i ++) cin >> a[i];
for(int i = 0; i < n; i ++) {
cin >> b[i];
if (a[i] - b[i] > 0) dis = max(dis, a[i] - b[i]);
}
for(int i = 0; i < n && f; i ++) {
if (max(0, a[i] - dis) == b[i]) continue;
f = 0;
}
cout << (f ? "YES" : "NO") << endl;
}
return 0;
}
C
模拟过程 直接输出就是
struct E {
int x, y;
}g[N];
int main() {
int t;
cin >> t;
while (t --) {
int n;
cin >> n;
for (int i = 1; i <= n; i ++) cin >> g[i].x;
for (int i = 1; i <= n; i ++) cin >> g[i].y;
int pre = -1;
for (int i = 1; i <= n; i ++) {
pre = max(pre, g[i].x);
cout << max(0, g[i].y - pre) << " ";
pre = max(pre, g[i].y);
}
cout << endl;
}
return 0;
}
D
k 个一组的窗口 转换为前缀和 求一下最小需要补上的值
const int N = 2e5 + 111;
int g[N], s[N];
int main() {
int t;
cin >> t;
while (t --) {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i ++) {
char ch; cin >> ch;
g[i] = ch == 'B';
s[i] = s[i - 1] + g[i];
}
int ans = k;
for (int i = k; i <= n; i ++) {
ans = min(ans, k - (s[i] - s[i - k]));
}
cout << ans << endl;
}
return 0;
}
E
⌊ a + b k ⌋ = ⌊ a k ⌋ + ⌊ b k ⌋ + ⌊ a % k + b % k k ⌋ \lfloor\frac{a + b}{k}\rfloor = \lfloor\frac{a}{k}\rfloor + \lfloor\frac{b}{k}\rfloor + \lfloor\frac{a \% k + b \% k}{k}\rfloor ⌊ka+b⌋=⌊ka⌋+⌊kb⌋+⌊ka%k+b%k⌋
先处理好一定有值的,剩余的丢map里面去匹配
const int N = 2e5 + 111;
int g[N], s[N];
signed main() {
int t;
cin >> t;
while (t --) {
int n, k;
cin >> n >> k;
long long sum = 0, ans = 0;
map<int, int> mp;
vector<int> ve;
for (int i = 1; i <= n; i ++) {
cin >> g[i]; sum += g[i] / k;
g[i] %= k;
mp[g[i]] ++;
}
for (int i = 0; i <= k; i ++)
if (mp.count(i) && mp.count(k - i)) {
int res = min(mp[i], mp[k - i]);
if (i == k - i) res /= 2;
ans += res;
mp[i] -= res;
mp[k - i] -= res;
if (!mp[i]) mp.erase(i);
if (!mp[k - i]) mp.erase(k - i);
}
for (auto [x, y] : mp)
while(y --) ve.push_back(x);
for (auto t = ve.begin(); t != ve.end();) {
int v = k - *t;
auto p = lower_bound(t + 1, ve.end(), v);
if (p != ve.end() && *p >= v) {
ans ++;
ve.erase(p);
}
t ++;
}
cout << sum + ans << endl;
}
return 0;
}
F
可以发现 字母只会在环里面进行循环,找到这个环的循环节就知道了这个环多少次为一轮
然后要求所有环最后回到起点,那么一定是所有循环节的最小公倍数
#define int long long
const int N = 2e5 + 111;
int g[N], v[N], p[N];
string s;
void dfs(int x, int idx) {
v[x] = idx;
if (!v[g[x]]) dfs (g[x], idx);
}
signed main() {
int t;
cin >> t;
while (t --) {
int n, idx = 0;
cin >> n >> s;
for (int i = 1; i <= n; i ++) v[i] = 0;
for (int i = 1; i <= n; i ++) cin >> g[i];
for (int i = 1; i <= n; i ++) {
if (v[i]) continue;
dfs(i, ++ idx);
}
int ans = 1;
for (int i = 1; i <= idx; i ++) {
string t = s, tm;
int cnt = 0;
do {
tm = t;
for (int j = 1; j <= n; j ++)
if (v[j] == i)
tm[g[j] - 1] = t[j - 1];
t = tm;
cnt ++;
} while (t != s);
ans = ans * cnt / __gcd(ans, cnt);
}
cout << ans << endl;
}
return 0;
}
G
可以看成一些区间 对于这些区间有 合并、拆开的操作
利用set来简化这些操作 set的大小就是答案
#define x first
#define y second
using namespace std;
#define endl "\n";
const int N = 2e5 + 111;
const int INF = 0x3f3f3f3f;
int g[N], v[N], p[N];
signed main() {
int t;
cin >> t;
while (t --) {
int n, k, x, v;
set<pair<int, int>> st;
vector<pair<int, int>> ve;
cin >> n >> k;
for (int i = 1; i <= n; i ++) cin >> g[i];
for (int i = 1; i <= n; i ++) {
int l = i, r = i;
while (i < n && g[i + 1] >= g[l]) i ++;
r = i;
st.insert({l, g[l]});
}
st.insert({n + 1, -INF});
while(k --) {
cin >> x >> v;
auto t = st.upper_bound({x, INF}); t --;
g[x] -= v;
if (t->second > g[x]) {
ve.clear();
auto p = st.lower_bound({x, -1});
while (1) {
if (p->second < g[x]) break;
ve.push_back(*p);
p ++;
}
for (auto i : ve) st.erase(i);
st.insert({x, g[x]});
}
cout << st.size() - 1 << " ";
}
cout << endl;
}
return 0;
}