XSYOJ-NOI2022模拟测试赛(八)

XSYOJ-NOI2022模拟测试赛(八)

英雄史观

题目

题目背景

EAM:
我现在在想英雄史观和群众史观的问题

EAM:
(当时并非绝对的英雄史观和绝对的群众史观)

EAM:
因为这两者前者恶毒后者愚蠢

风影剑醉:
仔细说说

EAM:
但是如果辩证的来看你更偏向哪一方?

EAM:
英雄史观唯心,但我不想弄得那么绝对

风影剑醉:
我个人肯定是支持英雄史观吧

EAM:
我知道马克思主义哲学说人民群众是社会历史主体,是社会变革的决定力量

风影剑醉:
我也知道

EAM:
英雄造时势

EAM:
但是吧

风影剑醉:
我就是因为 这个政治书跟我的好多理解不太一样,我才不选政治的

EAM:

EAM:
我理解他的科学依据

EAM:
并且很有道理

题目描述

现在 cyc 有 \(N\) 个英雄,他们构成了一个历史关系,这个历史关系恰好满足是一棵树。这棵树的每条边都有历史相关值 \(w\)

任意两个英雄 \(i\)\(j\) 的历史相关度 \(dist(i,j)\) 就是他们之间的历史关系相关值之和。

现在,rsx给定了 \(M\) 个关键英雄,cyc 要选择其中的 \(K\)( \(K\) 可以是一个你选择的值),满足 \(K\times C+\sum_{i=1}^M dist(a_i,b_i)\),其中 \(b_i\) 是选择的 \(K\) 个英雄里和第 \(i\) 个关键英雄 \(a_i\) 相关最密切的是 \(b_i\)

输入格式

第一行三个正整数 \(n,m,C\) 表示树的大小,关键点个数以及选择的代价。

接下来 \(n-1\) 行,每行三个整数 \(u,v,w\) 表示树上的一条边 \(u,v\) 历史相关值为 \(w\)

接下来一行 \(m\) 个数字,表示关键点。

输出格式

一行一个非负整数表示答案。

输入输出样例

post.in

5 3 3
1 2 1
2 3 1
3 4 1
3 5 1
1 4 5

post.out

7

数据规模与约定

对于全部的数据 \(m,n\le 3\times 10^3,1\le W,C\le 10^9\)

AC代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
// typedef long long ll;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define repg(i,u) for(int i=head[u];~i;i=edge[i].nxt)
#define lowbit(x) (x&(-x))
#define ls (o<<1)
#define rs (o<<1|1)
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define db double
#define endl '\n'
#define push_back emplace_back
inline int read(){
    int num=0,f=1;char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=0;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return f?num:-num;
}
const int MAXN=3010;
const int INF=1e17;
int n,m,C;
int a[MAXN];
vector<pii> G[MAXN];
int f[MAXN][MAXN],g[MAXN][MAXN];
// f_{u,i}: u 子树内尚未匹配完,剩余 j 个点
// g_{u,v}: u 子树内匹配完了,离 u 最近的点是 v
int dep[MAXN];
int siz[MAXN];
vector<int> pts[MAXN];
void dfs(int u,int fa,int fval){
    siz[u]=a[u];
    for(auto it: G[u]){
        int v=it.fi,w=it.se;
        if(v==fa)continue;
        dep[v]=dep[u]+w;
        dfs(v,u,w);
        siz[u]+=siz[v];
    }
    static int tmpf[MAXN],tmpg[MAXN];
    rep(j,0,siz[u])tmpf[j]=INF;
    f[u][0]=0;
    int nowsiz=0;
    for(auto it: G[u]){
        int v=it.fi;
        if(v==fa)continue;
        rep(j,0,nowsiz){
            rep(k,0,siz[v])tmpf[j+k]=min(tmpf[j+k],f[u][j]+f[v][k]);
        }
        for(auto x: pts[v])g[u][x]=INF;
        rep(j,0,nowsiz){
            for(auto x: pts[v]){
                int now=f[u][j]+g[v][x];
                now+=j*(dep[x]-dep[u]);
                g[u][x]=min(g[u][x],now);
            }
        }
        for(auto x: pts[u])tmpg[x]=INF;
        for(auto x: pts[u]){
            rep(j,0,siz[v]){
                int now=g[u][x]+f[v][j];
                now+=j*(dep[x]-dep[u]);
                tmpg[x]=min(tmpg[x],now);
            }
        }
        for(auto x: pts[u])g[u][x]=tmpg[x];
        for(auto x: pts[v])pts[u].push_back(x);
        nowsiz+=siz[v];
        rep(j,0,nowsiz){
            f[u][j]=tmpf[j];
            tmpf[j]=INF;
        }
    }
    per(j,nowsiz+a[u],a[u])f[u][j]=f[u][j-a[u]];
    per(j,a[u]-1,0)f[u][j]=INF;
    pts[u].push_back(u);
    g[u][u]=INF;
    rep(j,0,nowsiz+a[u]){
        int now=f[u][j];
        now+=C;
        g[u][u]=min(g[u][u],now);
    }
    for(auto x: pts[u])g[u][x]+=a[u]*(dep[x]-dep[u]);
    for(auto x: pts[u])f[u][0]=min(f[u][0],g[u][x]);
    rep(j,0,siz[u])f[u][j]+=j*fval;
}
void solve(){
    n=read(),m=read(),C=read();
    rep(i,1,n-1){
        int u=read(),v=read(),w=read();
        G[u].push_back(mp(v,w)),G[v].push_back(mp(u,w));
    }
    rep(i,1,m){
        a[read()]++;
    }
    dfs(1,0,0);
    printf("%lld\n",f[1][0]);
}
signed main(){
    // freopen("post2.in","r",stdin);
    // int T=read();
    int T=1;
    while(T--)solve();
}

我们设 \(f_{i,j}\) 表示 \(i\) 节点的子树,内还有 \(j\) 个点没有被匹配到选择的点上。当前的代价和(要计算这 \(i\) 个点到 \(j\) 的的路径长度)。

然后还需要设 \(g[i][j]\) 表示 \(i\) 子树的所有点已经被匹配,然后现在树外边来的点只能到 \(j\) 的最小代价。

我们考虑怎么转移。。首先 \(f\) 的转移就是个路径背包。然后考虑关于 \(g\) 的转移。

首先加入一棵子树,我们要算如果这个大树里的点匹配到子树里的点的最优。

然后子树里的点匹配到大树里的点的最优秀。

然后答案就是 \(F[1][0]\)

群众史观

题目

题目背景

谁是最伟大的人?

他说是人民,人民说是他。如果没有他,就没有这句话。

题目描述

你有一个矩阵。

\[A_{i,j} = \begin{cases} 1&i=j\\ 0&i\not = j \and i\vert j\\ C&\text{otherwise} \end{cases} \]

求他的行列式。

答案对于 \(998244353\) 取模

输入格式

一行一共两个正整数 \(N,C\)

输出格式

一行一个非负整数表示行列式的值。

输入输出样例

bigben.in


bigben.out


数据规模与约定

对于全部的数据 \(1\le C<998244353, 1\le N \le 10^{12}\)

AC代码
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {
		eng.seed(Seed);
		return;
	}
	int rnd(int l = 1, int r = 1000000000) {
		return uniform_int_distribution<int> (l, r)(eng);
	}
}
template <typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
template <typename T>
inline T read() {
	T x = 0;
	bool f = 0;
	char ch = getchar();
	while (!isdigit(ch)) {
		f = ch == '-';
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f ? -x : x;
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 262144, MOD = 998244353, inv2 = (MOD + 1) / 2;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) {
		if (y & 1) {
			ret = (long long) ret * x % MOD;
		} 
	}
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) {
		return x - MOD;
	}
	else if (x < 0) {
		return x + MOD;
	}
	else {
		return x;
	}
};
inline int ls(int k) {
	return k << 1;
}
inline int rs(int k) {
	return k << 1 | 1;
}
const int MAXL = 3e7 + 10;
long long N, C, A;
int F[MAXL], G[MAXL], pri[MAXL], w[MAXL], mnp[MAXL], vf[MAXN];
bool vis[MAXL];
int SF(long long x) {
	if (x < MAXL) {
		return F[x];
	}
	int id = N / x;
	if (vf[id]) {
		return vf[id];
	}
	int ret = 0;
	for (long long l = 2, r; l <= x; l = r + 1) {
		r = x / (x / l);
		ret = (ret + (r - l + 1) % MOD * SF(x / l)) % MOD;
	}
	return vf[id] = ((long long) ret * A + F[1]) % MOD;
}
int main() {
	std::ios::sync_with_stdio(0);
	cout << std::fixed << std::setprecision(8);
	cin.tie(0);
	cout.tie(0);
	qwq::init(20050112);
	cin >> N >> C;
	if (C == 1) {
		cout << (N <= 2);
		return 0;
	}
	A = (long long) C * Ksm(MOD + 1 - C, -1) % MOD;
	O(A);
	G[1] = Ksm(MOD + 1 - C, -1);
	for (int i = 2; i < MAXL; ++i) {
		if (!vis[i]) {
			pri[++*pri] = i;
			mnp[i] = i;
			w[i] = 1;
		}
		for (int j = 1; j <= *pri && pri[j] * i < MAXL; ++j) {
			if (i % pri[j]) {
				w[i * pri[j]] = w[i] + 1;
				mnp[i * pri[j]] = mnp[i] * pri[j];
				vis[i * pri[j]] = 1;
			}
			else {
				vis[i * pri[j]] = 1;
				w[i * pri[j]] = w[i];
				mnp[i * pri[j]] = mnp[i];
				break;
			}
		}
	}
	const int wp[] = {0, 2, 6, 30, 210, 2310, 30030, 510510, 9699690};
	mnp[1] = 1;
	for (int i = 2; i < MAXL; ++i) {
		mnp[i] = mnp[i / mnp[i]] * wp[w[i]];
		if (mnp[i] != i) {
			G[i] = G[mnp[i]];
			continue;
		}
		G[i] = G[1];
		for (int j = 2; j * j <= i; ++j) {
			if (i % j == 0) {
				G[i] = Mod(G[i] + G[j]);
				if (j * j != i) {
					G[i] = Mod(G[i] + G[i / j]);
				}
			}
		}
		G[i] = (long long) G[i] * A % MOD;
	}
	for (int i = 1; i < MAXL; ++i) {
		F[i] = Mod(G[i] + F[i - 1]);
	}
	int ANS = SF(N);
	O(F[1]);
	O(F[99]);
	ANS = (long long) Ksm(MOD + 1 - C, N % (MOD - 1)) * ANS % MOD;
	cout << ANS << '\n';
	// cout << (-3 / 2);
	return (0-0);
}

你发现,把矩阵写出来,比如咱写个 \(N=6\) 的矩阵。

\[\begin{bmatrix} 1& 0 &0 &0& 0 &0 \\ C& 1 &C &0& C &0\\ C&C&1&C&C&0\\ C&C&C&1&C&C\\ C&C&C&C&1&C\\ C&C&C&C&C&1\\ \end{bmatrix} \]

然后你发现,把每一行减去下一行,

就变成了一个上海森堡矩阵,每一行的 \(i\) 个位置变成了 \(1-C\),然后后面位置自己有变化(大概)。然后对于每个行除以 \(C\)。令 \(v=\frac{1-C}{C}\)

然后,考虑上海森堡矩阵其实是可以 \(O(N^2)\) 求行列式的。

就考虑设 \(f_i\) 表示当前的答案。然后可以直接考虑枚举置换环 dp。因为这个行列式里的每个置换,考虑经过 \(i\) 的置换,一定是 \(i\to j \to j - 1 \cdots \to i+1\to i\) 的。然后就可以dp。

然后就是这道题的巨大做法了。

那么,我们其实有设 \(f_j\) 是做到 \(j\) 的答案。然后考虑 \(f_i=f_{i-1}+v\sum_{j\vert i\and j \not = i} f_j-f_{j-1}\),然后考虑,不妨整个差分完事。

\(g_j=f_j-f_{j-1}\)。然后,有 $g_i=v\sum_{j\vert i\and j \not = i}g_j $。

我们考虑怎么求整个东西,应该可以杜教筛。

具体咋做。

社论 - 讨论 - LibreOJ (loj.ac)

这个帖子。

会解答你的疑惑。

然后如何 \(O(n^{\frac{2}{3}})\) 预处理,可以选择代表元之后 \(O(\sqrt v)\) 的做一个代表元即可。

我们是最好的朋友

题目

题目背景

回忆了一下这些年的朋友圈
(以前还是真的能发)
曾经以为走不出的日子,现在都回不去了
曾经以为永远的朋友也大多走着走着就散了
但,愿往事如风,少年眉眼带笑,在新的陪伴鼓励下,清醒坚强,纤尘不染

题目描述

你有个算分治FFT复杂度的程序

def work(n) 
	return (p + 1) * 2 ^ p;
def solve(n)
	if n = 1
		return work(1);
	return solve(ceil(n / 2)) + solve(floor(n / 2)) + work(n);

然后他想要对于一个 二进制数字 \(N\),查询 solve(N) 的答案。

然而这太简单了,你还准备添加一些修改操作

  • 1 l r\([l,r]\) 中的数字 \(0\to 1\), \(1\to 0\).
  • 2 l r\([l,r]\) 中的数字都变成 \(0\)
  • 3 l r\([l,r]\) 中的数字都变成 \(0\)
  • 4 l r 查询 \([l,r]\) 之间二进制数字的答案,右边是高位。

输入格式

一行一共两个正整数 \(N,M\)

第二行一个长度为 \(N\) 的01串 \(S\)

接下来 \(M\) 行,每行三个数字 \(op,l,r\) 如题意。

输出格式

每行对于每个 \(op=4\) 的询问输出你的答案。

输入输出样例

run1.in

5 20
00010
2 4 4
1 2 5
2 1 4
3 5 5
4 2 4
2 2 5
4 2 3
1 1 4
4 2 5
4 2 3
4 1 4
2 3 4
2 1 4
1 5 5
3 1 5
3 5 5
3 1 2
2 1 1
3 1 2
4 1 5

run1.out

0
0
75
19
235

run2.in

20 8
00001011001011101011
2 9 20
3 3 16
4 6 18
3 4 10
1 2 7
2 7 12
3 11 15
4 1 11

run2out

159739
103426

数据规模与约定

对于所有的数据,满足 \(1\le n,m\le 10^5,1\le l\le r\le n\)

AC代码
// 这是一份爆标做法 N log ^ 2 N
// 可以优化到 N log N 但是没必要
// 哦 可以使用 find_first 线段树上二分即可 优化到 O(N \log N)
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {
		eng.seed(Seed);
		return;
	}
	int rnd(int l = 1, int r = 1000000000) {
		return uniform_int_distribution<int> (l, r)(eng);
	}
}
template <typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
template <typename T>
inline T read() {
	T x = 0;
	bool f = 0;
	char ch = getchar();
	while (!isdigit(ch)) {
		f = ch == '-';
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f ? -x : x;
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 1e5 + 10, MOD = 998244353, inv2 = (MOD + 1) / 2;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) {
		if (y & 1) {
			ret = (long long) ret * x % MOD;
		} 
	}
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) {
		return x - MOD;
	}
	else if (x < 0) {
		return x + MOD;
	}
	else {
		return x;
	}
};
inline int ls(int k) {
	return k << 1;
}
inline int rs(int k) {
	return k << 1 | 1;
}
int N, M, p[MAXN], ip[MAXN], A[MAXN];
inline int get(int l, int r) {
	return Mod(p[r + 1] - p[l]);
}
struct Segment_Tree {
	int SZ, rev[MAXN * 4], cnt[MAXN * 4], val[MAXN * 4], tag[MAXN * 4];
	inline void up(int u) {
		cnt[u] = cnt[ls(u)] + cnt[rs(u)];
		val[u] = Mod(val[ls(u)] + val[rs(u)]);
		return;
	}
	inline void puttag(int nw, int rtag, int atag, int l, int r) {
		if (atag != -1) {
			tag[nw] = atag;
			rev[nw] = 0;
			val[nw] = atag ? get(l, r) : 0;
			cnt[nw] = atag ? r - l + 1 : 0;
		}
		if (rtag) {
			rev[nw] ^= 1;
			val[nw] = Mod(get(l, r) - val[nw]);
			cnt[nw] = r - l + 1 - cnt[nw];
		}
	}
	inline void down(int nw, int l, int r) {
		int mid = (l + r) / 2;
		puttag(ls(nw), rev[nw], tag[nw], l, mid);
		puttag(rs(nw), rev[nw], tag[nw], mid + 1, r);
		rev[nw] = 0;
		tag[nw] = -1;
		return;
	}
	void build(int _N) {
		function<void(int, int, int)> dfs = [&] (int nw, int l, int r) -> void {
			tag[nw] = -1;
			if (l == r) {
				val[nw] = A[l] * p[l];
				cnt[nw] = A[l];
				return;
			}
			int mid = (l + r) / 2;
			dfs(ls(nw), l, mid);
			dfs(rs(nw), mid + 1, r);
			return up(nw);
		};
		SZ = _N;
		return dfs(1, 1, SZ);
	}
	void reverse(int ql, int qr) {
		function<void(int, int, int)> dfs = [&] (int nw, int l, int r) -> void {
			if (ql <= l && r <= qr) {
				return puttag(nw, 1, -1, l, r);
			}
			int mid = (l + r) / 2;
			down(nw, l, r);
			if (ql <= mid) {
				dfs(ls(nw), l, mid);
			}
			if (mid < qr) {
				dfs(rs(nw), mid + 1, r);
			}
			return up(nw);
		};
		return dfs(1, 1, SZ);
	}
	void assign(int ql, int qr, int qx) {
		function<void(int, int, int)> dfs = [&] (int nw, int l, int r) -> void {
			if (ql <= l && r <= qr) {
				return puttag(nw, 0, qx, l, r);
			}
			int mid = (l + r) / 2;
			down(nw, l, r);
			if (ql <= mid) {
				dfs(ls(nw), l, mid);
			}
			if (mid < qr) {
				dfs(rs(nw), mid + 1, r);
			}
			return up(nw);
		};
		return dfs(1, 1, SZ);
	}
	// 找到 [ql, qr] 之间的最靠右边的 1
	int findr(int ql, int qr) {
		if (ql > qr) {
			return -1;
		}
		int tot = 0;
		function<int(int, int, int)> dfs = [&] (int nw, int l, int r) -> int {
			++tot;
			if (ql <= l && r <= qr) {
				// O(ql);
				if (!cnt[nw]) {
					return -1;
				}
				if (l == r) {
					return l;
				}
				else {
					down(nw, l, r);
					int mid = (l + r) / 2;
					if (cnt[rs(nw)]) {
						return dfs(rs(nw), mid + 1, r);
					}
					else  {
						return dfs(ls(nw), l, mid);
					}
				}
			}
			down(nw, l, r);
			int mid = (l + r) / 2;
			if (mid < qr) {
				int ret = dfs(rs(nw), mid + 1, r);
				if (ret != -1) {
					return ret;
				}
			}
			if (ql <= mid) {
				int ret = dfs(ls(nw), l, mid);
				if (ret != -1) {
					return ret;
				}
			}
			return -1;
		};
		int ret = dfs(1, 1, SZ);
		// O(tot);
		return ret;
	}
	int query(int ql, int qr) {
		function<int(int, int, int)> dfs = [&] (int nw, int l, int r) -> int {
			if (ql <= l && r <= qr) {
				return val[nw];
			}
			int mid = (l + r) / 2, ret = 0;
			down(nw, l, r);
			if (ql <= mid) {
				ret = dfs(ls(nw), l, mid);
			}
			if (mid < qr) {
				ret = Mod(ret + dfs(rs(nw), mid + 1, r));
			}
			return ret;
		};
		return dfs(1, 1, SZ);
	}
} T;
int getf(int x) {
	return (p[x] * (x + 1LL) + 1) % MOD;
}
int qry(int l, int r) {
	int k = T.findr(l, r);
	// 没有 1 存在
	// O(k);
	if (k == -1) {
		return 0;
	}
	int m = T.findr(l, k - 1);
	if (m == -1) {
		// 2 的 幂次
		k -= l;
		return (k + 1LL) * (k + 2LL) / 2 % MOD * p[k] % MOD;
	}
	m -= l;
	k -= l;
	// 最高位贡献
	int ANS = (k + 1LL) * (k + 2LL) / 2 % MOD * p[k] % MOD;
	// 加到第一个
	ANS = Mod(ANS + getf(k + 1));
	// 后面除了最高位和次高位的贡献
	ANS = (ANS + getf(k - m) * ((long long) T.query(l, r) * ip[l] % MOD - p[k] - p[m] + 2LL * MOD)) % MOD;
	// 还有就是怎么加到次高位
	// O(ANS);
	// O(k);
	// O(m);
	ANS = (ANS + p[m] - 1 + p[k] * (k * 2LL - m + 3) % MOD * m % MOD * inv2) % MOD;
	return ANS;
}
int main() {
	// freopen("run.in", "r", stdin);
	// freopen("run.out", "w", stdout);
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	qwq::init(20050112);
	N = read <int> ();
	// O(N);
	M = read <int> ();
	// O(M);
	for (int i = 1; i <= N; ++i) {
		A[i] = getchar() - '0';
	}
	p[0] = ip[0] = 1;
	for (int i = 1; i < MAXN; ++i) {
		p[i] = (long long) p[i - 1] * 2 % MOD;
		ip[i] = (long long) ip[i - 1] * inv2 % MOD;
	}
	T.build(N);
	for (int opt, l, r; M--; ) {
		opt = read <int> ();
		l = read <int> ();
		r = read <int> ();
		if (opt == 1) {
			T.reverse(l, r);
		}
		else if (opt == 2) {
			T.assign(l, r, 0);
		}
		else if (opt == 3) {
			T.assign(l, r, 1);
		}
		else {
			printf("%d\n", qry(l, r));
		}
	}
	// cout << (-3 / 2);
	return (0-0);
}

我们考虑,如果 \(solve(N)\) 变成 \(solve(N + 1)\) 他会怎么样呢,打个表发现,他多了两个 \(work(x)\)

\(w(x)=(x+1)\times 2 ^ x\)

具体地说,是一个 \(w(0)\),还有一个 \(work(最高位1-最低位1)\)

然后,我们就可以做,考虑 \(O(qn)\),每次暴力找出个下表最大和次大的一,然后剩下那些二进制数字的值,然后就可以计算 \(solve(x)\) 的值了。

加上修改,我们只要用线段树维护区间的值和1的个数即可。

posted @ 2022-03-10 08:39  siriehn_nx  阅读(122)  评论(0编辑  收藏  举报