ABC 406
ABC 406
C ~
本来只想整理EF题的,但好像C有难度,于是一块整理
(这个题目也挺魔性)

其实就是关于山峰山谷的问题
考虑将山峰和山谷先求出来有哪些
然后可以对每个点求贡献
代码:

E Popcount Sum 3
距离正解最近的一次,但没调出来

发现数据范围巨大,想到数位DP
说句实话,这不是数位DP板子吗
但我不会写/ll
这个题可以当做很好的数位DP的练习题
设f[i][j][k]表示考虑二进制下前i位,选了j个1,是否紧贴上界n
直接从高位往低位转移即可
具体看代码实现
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
if(b==0) return 1;
if(b==1) return a%p;
int c=ksm(a,b/2,p);
c=c*c%p;
if(b%2==1) c=c*a%p;
return c%p;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int MOD=998244353;
int dp[65][65][2],sum[65][65][2];
int cnt,ans[65];
signed main()
{
//freopen("filename.in", "r", stdin);
//freopen("filename.out", "w", stdout);
int T=read();
while(T--){
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
int n=read(),x=read();
cnt=0;
while(n>0){
ans[++cnt]=n%2;
n/=2;
}
dp[cnt+1][x][1]=1;
for(int i=cnt;i>=1;i--){
for(int j=0;j<=x;j++){
for(int k=0;k<2;k++){
int maxx=0;
if(k==1) maxx=ans[i];
else maxx=1;
for(int q=0;q<=maxx;q++){
int now=0;
if(k&&q==maxx) now=1;
int nw=j;
if(q==1) nw--;
if(nw<0) continue;
jiaa(dp[i][nw][now],dp[i+1][j][k]);
jiaa(sum[i][nw][now],sum[i+1][j][k]);
if(q==1){
int summ=((1LL<<(i-1))%MOD)*dp[i+1][j][k]%MOD;
jiaa(sum[i][nw][now],summ);
}
}
}
}
}
cout<<(sum[1][0][1]+sum[1][0][0])%MOD<<'\n';
}
return 0;
}
注意运算符优先级!!!
注意位运算时<<需要1LL!!!
F - Compare Tree Weights

首先观察发现,断开一条边后,答案为整棵树的权值和减一颗子树的权值和
现在题目变成
1.单点加权值
2.快速求子树和
好像会树链剖分的到这里就秒了
但我不会啊
所以有一个重要的性质:
在dfs序下,子树上所有点是连续的
所以变成单点加区间求和
树状数组!!!
做完了!
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct node
{//树状数组
int n;
vector<ll> f;
node(int _n): n(_n), f(n + 1, 0) {}
void update(int i, ll v)
{
for(; i <= n; i += i & -i)
f[i] += v;
}
ll qry(int i)
{
ll s = 0;
for(; i > 0; i -= i & -i)
s += f[i];
return s;
}
ll qry2(int l, int r)
{
return qry(r) - qry(l - 1);
}
}tree(300001);
vector<vector<pair<int, int> > > e(300001);
vector<pair<int, int> > ed(300001);
int aa[300001],tou[300001],pa[300001],son[300001];
vector<pair<int, int> > st;
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n - 1; i++)
{
int u, v;
cin >> u >> v;
ed[i] = {u, v};
e[u].push_back({v, i});
e[v].push_back({u, i});
}
int nw = 0;
st.reserve(n * 2);
st.emplace_back(1, 0);
pa[1] = 0;
while(!st.empty())//处理dfs序
{
int u = st.back().first;
int &ci = st.back().second;
if(ci == 0)
{
aa[u] = ++nw;
}
if(ci < (int)e[u].size())
{
auto [v, ei] = e[u][ci++];
if(v == pa[u])
continue;
pa[v] = u;
son[ei] = v;
st.emplace_back(v, 0);
}
else
{
tou[u] = nw;
st.pop_back();
}
}
for(int i = 1; i <= n; i++)
{
tree.update(aa[i], 1);
}
int T;
cin >> T;
while(T--)
{
int op;
cin >> op;
if(op == 1)
{
int x;
ll w;
cin >> x >> w;
tree.update(aa[x], w);//单点加
}
else if(op == 2)
{
int y;
cin >> y;
int c = son[y];
ll s1 = tree.qry2(aa[c], tou[c]);//区间求和
ll s2 = tree.qry(n);
ll xxx = s1 - (s2 - s1);//计算答案
if(xxx < 0)
xxx = -xxx;
cout << xxx << "\n";
}
}
return 0;
}

浙公网安备 33010602011771号