Problem - D1 - Codeforces
题目保证y <= x
因为 y <= x 所以尽量不操作相邻的数,只有当a ,b 只有两个不相同的数时,将这两个数变为相同,需要 两次 y 操作,如果这两个数正好相邻 那么需要一次x操作,则需要比较一下 代价,
min(x , 2 * y); 对于其他情况都可以转换为 y 操作。
#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int t;
int num[N];
void solve()
{
int n,x,y;cin >> n >> x >> y;
string a,b;cin >> a >> b;
int cnt = 0;
for(int i = 0;i < n;i ++)
{
if(a[i] != b[i])num[++ cnt] = i;
}
if(cnt % 2){cout << "-1" << endl;return ;}
if(cnt == 0){cout << "0" << endl;return ;}
if(cnt == 2){
if(num[1] + 1 == num[2]){
cout << min(x , 2 * y) << endl;
}
else cout << y << endl;
}
else {
cout << cnt * y / 2 << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t --)solve();
return 0;
}
Problem - 1697C - Codeforces
对于两种操作,每次都将a向后移动,将c向前启动,a,c的相对位置不会改变。
所以我们不需要考虑b的位置,将b全部删去,考虑a,c的相对位置即可。
#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int t;
void solve()
{
int n;cin >> n;
string a,b;cin >> a >> b;
int cnt2 = 0;
int cnt1 = 0;
int j = 0;
for(int i = 0;i <= n;i ++)
{
while(b[j] == 'b')cnt2 ++,j ++;
if(a[i] == 'b'){cnt1 ++;continue;};
if(a[i] != b[j] || a[i] == 'a' && i > j || a[i] == 'c' && i < j)
{
cout << "NO" << endl;
return ;
}
j ++;
}
while(b[j] == 'b')cnt2 ++,j ++;
if(cnt1 != cnt2)
{
cout << "NO" << endl;
return ;
}
cout << "YES" <<endl;
return ;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t --)solve();
return 0;
}
Problem - 1696C - Codeforces
容易发现两个操作本质上是互逆的,因此只要将 a 和 b 中的所有元素拆开再比较是否相同即可。
注意最后的数字总数可能过大,所以将a拆开后,对于b数组一边拆一边比;
大佬代码
#include<bits/stdc++.h>
#define N 1000005
#define int long long
using namespace std;
int T,n,m,k,a[N],b[N],p1,p2,sum1,sum2;
struct node{
int num,sum;
};
stack<node>s;
signed main(){
cin>>T;
while(T--){
cin>>n>>m;
bool flag=1;
sum1=sum2=0;
while(!s.empty())s.pop();
for(int i=1;i<=n;i++){
cin>>a[i],sum1+=a[i];
int tmp=1;
while(a[i]%m==0)a[i]/=m,tmp*=m;
s.push((node){
a[i],tmp
});
}
cin>>k;
for(int i=1;i<=k;i++)cin>>b[i],sum2+=b[i];
if(sum1!=sum2){
puts("No");
continue;
}
for(int i=k;i>=1;i--){
int tmp=1;
while(b[i]%m==0)b[i]/=m,tmp*=m;
while(tmp){
if(s.empty()||b[i]!=s.top().num){
flag=0;
break;
}
if(tmp>=s.top().sum)tmp-=s.top().sum,s.pop();
else {
s.top().sum-=tmp;
tmp=0;
}
}
if(!flag)break;
}
puts(flag?"Yes":"No");
}
}
P3478 [POI2008] STA-Station - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
换根dp 模板题
暴力做法 dfs 暴力求每个点的深度之和,但是我们发现对于x的节点 我们如果求出它的父节点的深度,x的节点的深度之和可以通过父节点的深度计算出来,
当x为根节点时,x的父节点的所有子节点深度会增加1 ,而x 包含x 的所有子节点深度会减小1;
所以我们第一遍dfs维护每个节点子节点个数siz[N]数组和每个节点的深度dep[N]数组。
第二遍dfs 算出每个节点的深度之和
但是我们最开始的第一个节点需要暴力求出来,这也就是为什么要维护dep[N]数组
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
const int N = 1e6 + 10;
#define int long long
int n,m;
vector<int> tr[N];
int siz[N];
int dep[N];
int f[N];
void dfs(int u,int fa)
{
siz[u] = 1,dep[u] = dep[fa] + 1;
for(int v : tr[u])
{
if(v != fa){
dfs(v , u);
siz[u] += siz[v];
}
}
}
void dfs1(int u,int fa)
{
for(int v : tr[u])
{
if(v != fa)
{
f[v] = f[u] - siz[v] + n - siz[v];
dfs1(v , u);
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1;i < n;i ++)
{
int a,b;cin >> a >> b;
tr[a].push_back(b);
tr[b].push_back(a);
}
dfs(1 , -1);
for(int i = 1;i <= n;i ++)f[1] += dep[i];
dfs1(1 , -1);
int ans = 0;
int id = 0;
for(int i = 1;i <= n;i ++)if(ans < f[i]){
ans = f[i],id = i;
}
cout << id << endl;
return 0;
}