版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
A - Chips Moving
分析:不改变奇偶的情况下是免费的,那么数一下奇数和偶数的个数就可以了。
#include "bits/stdc++.h"
using namespace std;
int main(){
int n;
int od=0,ev=0;
cin>>n;
int x;
while(n--){
cin>>x;
if(x&1)od++;
else ev++;
}
cout<<min(od,ev)<<endl;
}
B - Bad Prices
分析:记录一个后缀最小值,然后倒着扫一遍就可以了。
#include "bits/stdc++.h"
using namespace std;
int a[150004];
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
int ans = 0;
int mini = 1e9;
for (int i = n; i >= 1; --i) {
if(a[i] > mini) ans ++;
else mini = a[i];
}
cout<<ans<<endl;
}
}
C - Book Reading
分析:简单分析一下可以发现,最终加上去的答案是一个循环节,找到循环节然后计算一下就可以了。
#include "bits/stdc++.h"
using namespace std;
int a[150004];
int main() {
int t;
cin >> t;
while (t--) {
long long n,m;
cin >> n >> m;
long long now = m;
long long ans = 0;
while(now <= n){
ans += now % 10;
now += m;
if(now % 10 == m % 10){
now -= m;
break;
}
}
ans = ans * (n / now);
now = now * (n / now);
while(now <= n){
ans += now % 10;
now += m;
}
cout<<ans<<endl;
}
}
D1 - Equalizing by Division (easy version)&&D2 - Equalizing by Division (hard version)
分析:所有的可能出现的值理论上最多只有nlogn个,那么记录所有值到达这个值的步数,对于个数>=k的去前k个就可以了。
#include "bits/stdc++.h"
using namespace std;
int a[200004];
map<int,vector<int>>mp;
int main() {
int n,k;
cin>>n>>k;
for (int i = 1; i <= n; ++i) {
scanf("%d",&a[i]);
int temp = a[i];
int cnt = 0;
while(temp){
if(mp.count(temp))mp[temp].push_back(cnt);
else {
vector<int>v;
mp[temp]=v;
mp[temp].push_back(cnt);
}
temp >>= 1;
cnt ++;
}
}
int ans= 1e9;
for(auto it : mp){
if(it.second.size() >= k){
sort(it.second.begin(),it.second.end());
int sum = 0;
for (int i = 0; i < k; ++i) {
sum += it.second[i];
}
ans = min(ans,sum);
}
}
printf("%d\n",ans);
}
E - Two Small Strings
分析:总共情况只有那么几种,模拟一下就可以了。
#include "bits/stdc++.h"
using namespace std;
bool check(string s,string t){
for (int i = 0; i + t.size() <= s.size(); ++i) {
bool ok =1;
for (int j = i; j < i + t.size(); ++j) {
if(s[j]!=t[j-i])ok=0;
}
if(ok)return 1;
}
return 0;
}
int main() {
int n;
string s,t;
cin>>n>>s>>t;
string ye[6]={"abca","acba","bacb","bcab","cabc","cbac"};
for (int i = 0; i < 6; ++i) {
if(!check(ye[i],s) && !check(ye[i],t)){
ye[i].erase(--ye[i].end());
puts("YES");
for (int j = 0; j < n; ++j) {
cout<<ye[i];
}
puts("");
return 0;
}
}
if(t[0]==s[0]){
puts("YES");
char t1 = t[1],t2=s[1];
for (int i = 0; i < n; ++i) {
putchar(t1);
putchar(t2);
}
for (int i = 0; i < n; ++i) {
putchar(t[0]);
}
}
else if(t[1] == s[1]){
puts("YES");
char t1 = t[0],t2=s[0];
for (int i = 0; i < n; ++i) {
putchar(t[1]);
}
for (int i = 0; i < n; ++i) {
putchar(t1);
putchar(t2);
}
}
else if(t[1]==s[0] && s[1] == t[0]){
puts("YES");
char temp;
for (int i = 0; i < 3; ++i) {
if(i+'a'!=t[1] && i+'a'!=t[0])temp=i+'a';
}
for (int i = 0; i < n; ++i) {
putchar(s[0]);
}
for (int i = 0; i < n; ++i) {
putchar(temp);
}
for (int i = 0; i < n; ++i) {
putchar(s[1]);
}
}
}
F - Unstable String Sort
分析:就这题稍微有点意思。
我们要求出一个字符串,这个字符串最少有K个字符,同时给出两个1到n的置换p,q,要求对于置换p,q在置换后的字符串是单调非减的。那么我们先默认p置换已经有序了,那么我们只需要求出在这种情况下,置换q也有序就可以了。
首先我们需要找出一个置换t使得置换p置换t后于置换q等效,然后现在对于置换t这个序列,对于i<j有s[i]<=s[j],对于t[i]<t[j]有s[i]<=s[j],那么从t[i]=1的位置开始,如果t[i]=x的位置p前面不存在t[j]>x,并且此时字母已经填到c,那么此时字母可以加1,即d,否则还是c,然后把p前面的还未赋值的位置赋值就可以了。
然后再根据两个置换pt还原即可。pq写反,WA的惨无人道
#include "bits/stdc++.h"
using namespace std;
int p[200004], q[200004];
int tp[200004];
int tp2[200004];
char ans[200004];
char res[200004];
int aaa[200004];
int main() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
scanf("%d", &p[i]);
tp[p[i]] = i;
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &q[i]);
aaa[i]=q[i];
q[i] = tp[q[i]];
tp2[q[i]] = i;
}
if(k==1){
puts("YES");
for (int i = 0; i < n; ++i) {
putchar('a');
}
return 0;
}
char now = 'a' - 1;
int last = 1;
int maxi = 0;
for (int i = 1; i <= n; ++i) {
int pos = tp2[i];
if (pos < last)continue;
if (i > maxi)now++;
if (now > 'z' ) now--;
for (int j = last; j <= pos; ++j) {
ans[j] = now;
maxi = max(maxi, q[j]);
}
last = pos + 1;
}
if (ans[n] - 'a' + 1 < k) {
return 0 * puts("NO");
}
for (int i = 1; i <= n; ++i) {
res[p[q[i]]] = ans[i];
}
puts("YES");
for (int i = 1; i <= n; ++i) {
putchar(res[i]);
}
puts("");
}
G - Path Queries
分析:将询问离线,然后按边权大小将点加进去,维护一下每个连通分量的点的个数,每个连通分量的贡献应该是cn2,写个带权并查集就可以了。
#include "bits/stdc++.h"
using namespace std;
struct edge {
int u, v, w;
bool friend operator<(edge a, edge b) {
return a.w < b.w;
}
} e[200004];
int fa[200004];
int num[200004];
int Find(int a) {
if (a == fa[a])return a;
else return fa[a] = Find(fa[a]);
}
pair<int, int> que[200004];
long long ans[200004];
int main() {
int n, m;
cin >> n >> m;
int x, y, z;
for (int i = 0; i <= n; ++i) {
fa[i] = i;
num[i] = 1;
}
for (int i = 0; i < n - 1; ++i) {
scanf("%d%d%d", &x, &y, &z);
e[i] = {x, y, z};
}
sort(e, e + n - 1);
for (int i = 0; i < m; ++i) {
scanf("%d", &x);
que[i] = make_pair(x, i);
}
sort(que, que + m);
long long res = 0;
int pos = 0;
for (int i = 0; i < m; ++i) {
while (pos < n - 1 && e[pos].w <= que[i].first) {
int fx = Find(e[pos].u);
int fy = Find(e[pos].v);
res -= 1LL * (num[fx] - 1) * num[fx] / 2;
res -= 1LL * (num[fy] - 1) * num[fy] / 2;
res += 1LL * (num[fx] + num[fy] - 1) * (num[fx] + num[fy]) / 2;
fa[fx] = fy;
num[fy] += num[fx];
pos ++;
}
ans[que[i].second]=res;
}
for (int i = 0; i < m; ++i) {
printf("%lld ",ans[i]);
}
}