yuwj  

写在前面

这场是周度VP,日常训练,

找的是上半年广工校赛,不是下半年新生赛!

新生赛题解还在制作中...

G

题意:

长度为 $n$ 的排列,允许交换任意的距离为 $x$ 的数字使数组升序,问,这样的 $x$ 有多少个?

思路:

观察发现,

1.相隔 $x$ 的所有数字经过任意次交换一定可以升序,可以按照对 $x$ 取模将数字分 $x$ 个块

2.想要将数组升序,每个数字肯定是从位置 $pos[i]$ 转移到 $i$,达成这个条件必须每个值都在同一个块内,也就是 $pos[i] \equiv i \mod{x}$

考虑如何将条件转化为对整个数组判断,发现最后取到的值满足 $G = gcd_{i=1}^{n}(|pos[i] - i|)$

$x$ 的取值就是 $G$ 的因子,则答案就是 $G$ 的因子个数

时间复杂度 $O(n+\sqrt{n})$

// 对于任意的 x,满足 pos[i]=i(mod x),
// 则 G = gcd(all(i)),
// 则答案的取值为 G 的因子个数
void solve(){
	cin >> n;
	vector<int> num(n+1), pos(n+1);
	For(i,1,n) cin >> num[i], pos[num[i]] = i;

	int G = 0;
	for(int i=1;i<=n;++i) G = gcd(G,abs(pos[i]-i));
	
	int ans = 0;
	for(int i=1;i<=G/i;++i){
		if(G%i==0){
			ans++;
			if(i*i!=G) ans++;
		}
	}

	if(G==0) ans = n;
	cout << ans << '\n';
}

I

题意:

$S$ 中匹配到所有 $T$ 的出现区间,在区间内标点表示区间染色,求所有区间染色的最少标记点数量

思路:

切到所有出现区间段,维护上一个选择的右端点,若当前左端点 $>$ 右端点,则 $ans++$,更新 $last$

H

题意:

$01$ 字符串切成两块的 $1$ 的数量减去 $0$ 的数量的乘积最大值

思路:

维护前缀和,枚举划分点,注意细节:答案可能为负数,初始化负无穷,不能选择 $n$ 位置作为划分点

void solve(){ 
	cin >> n >> s, s = " " + s;
	vector<int> cnt0(n+1), cnt1(n+1);
	for(int i=1;i<=n;++i){
		cnt1[i] = cnt1[i-1], cnt0[i] = cnt0[i-1];
		if(s[i]=='0') cnt0[i]++;
		else cnt1[i]++;
	}

	ll ans = -LLONG_MAX; // 答案可能是负数,不能枚举非法点 n
	for(int i=1;i<n;++i){
		int l = cnt1[i] - cnt0[i], r = cnt1[n] - cnt1[i] - (cnt0[n] - cnt0[i]);
		// cerr << l << ' ' << r << '\n';
		// r = max(r,0ll), l = max(l,0ll);
		ans = max(ans, 1ll*l*r);
	}cout << ans << '\n';
}

F

思路:

经典枚举分界点,处理前后缀,答案取min就好了

考虑前后缀如何维护,先找到该位置出现的第一个区间起点,然后合并区间,这里可以用set维护信息来做

考验码力的时候到了

struct Node{
	int l,r,cnt;
	bool operator<(const Node o) const{
		return l<o.l;
	}
};

void Solve(){
	cin >> n >> k;
	vector<int> num(n+1);
	For(i,1,n) cin >> num[i];
	
	set<int> L,R;
	vector<int> pre(n+1),suf(n+2);

	{
		set<Node> S;
		for(int i=1;i<=n;++i){
			int L = num[i], wait = 0;
			auto it = S.lower_bound({L,0,0});

			//看左邻居是否覆盖到 t[i]
			if(it != S.begin()){
				auto last = prev(it);
				if(last->r > L) L = last->r;
			}

			wait += (L-num[i]);
			int R = L+k, ncnt = 1;		
			// 向右合并:把右侧与 [L,R) 交/相邻的段整体右移
			it = S.lower_bound({L,0,0});
			while(it != S.end() && it->l <= R){
				int d = R - it->l;
				R = it->r + d, ncnt += it->cnt;
				wait += 1ll*d*(it->cnt);
				it = S.erase(it);
			}

			// 与左侧相邻段合并(如果恰好相接)
			it = S.lower_bound({L,0,0});
			if(it!=S.begin()){
				auto last = prev(it);
				if(last->r==L){
					L = last->l, ncnt += last->cnt;
					S.erase(last);
				}
			}
			S.insert({L,R,ncnt});
			pre[i] = pre[i-1] + wait;
		}
	}

	// 后缀合并区间
	set<Node> S;
	for(int i=n;i>=1;--i){
		int L = num[i], wait = 0;
		auto it = S.lower_bound({L,0,0});

		//看左邻居是否覆盖到 t[i]
		if(it != S.begin()){
			auto last = prev(it);
			if(last->r > L) L = last->r;
		}

		wait += (L-num[i]);
		int R = L+k, ncnt = 1;		
		// 向右合并:把右侧与 [L,R) 交/相邻的段整体右移
		it = S.lower_bound({L,0,0});
		while(it != S.end() && it->l <= R){
			int d = R - it->l;
			R = it->r + d, ncnt += it->cnt;
			wait += 1ll*d*(it->cnt);
			it = S.erase(it);
		}

		// 与左侧相邻段合并(如果恰好相接)
		it = S.lower_bound({L,0,0});
		if(it!=S.begin()){
			auto last = prev(it);
			if(last->r==L){
				L = last->l, ncnt += last->cnt;
				S.erase(last);
			}
		}

		S.insert({L,R,ncnt});
		
		suf[i] = suf[i+1] + wait;
	}

	// For(i,1,n) cerr << pre[i] << " \n"[i==n];
	// For(i,1,n) cerr << suf[i] << " \n"[i==n];

	ll ans = LLONG_MAX;
	for(int i=1;i<=n;++i) ans = min(ans, pre[i] + suf[i+1]);
	cout << ans << '\n';
}

K

经典数数题,就是题解那个意思,推到最后公式是
$$
ans = \sum_{i=1}^{min(k,n-k+1)} \binom{n-k+1}{i} \binom{k-1}{i-1} m^i (m-1)^{k-i}
$$

void Solve(){
	cin >> n >> m >> k;
	if(m == 1){
		cout << binom(n-k+1,k) <<'\n';
		return;
	}

	ll ans = 0, pwm = m, pwm1 = qmi(m-1,k-1,Mod), invm = inv(m-1);
	for(int i=1;i<=min(k,n-k+1);++i){
		ll tmp = 1ll*binom(k-1,i-1)%Mod*binom(n-k+1,i)%Mod;
		ans = (ans + tmp*pwm%Mod*pwm1%Mod) % Mod;
		pwm = pwm*m%Mod, pwm1 = pwm1*invm%Mod;
	}

	cout << ans << '\n';
}

D

用线段树的方式做 01 背包即可

代码是抄的

#include<bits/stdc++.h>
using namespace std;
#define x first 
#define y second 
//#define int long long
#define lowbit(x) (x&(-x))
#define pii pair<int,int>
#define debug(x) {cerr << #x << " = " << x << "\n";}
const int N = 1e3 + 1,M = 1e4 + 1;
vector<int>wi(N),vi(N);
const int D = __lg(N) + 1;
int dpl[D][N][M],dpr[D][N][M];
void build(int l,int r,int dp) {
    if(l == r) return ;
    int mid = l + r >> 1;
    for(int i = wi[mid]; i < M; i++) {
        dpr[dp][mid][i] = vi[mid];
    }
    for(int i = wi[mid + 1]; i < M; i++) {
        dpl[dp][mid + 1][i] = vi[mid + 1];
    }
    for(int i = mid - 1; i >= l; i--) {
        for(int j = 0; j < M; j++) {
            dpr[dp][i][j] = dpr[dp][i + 1][j];
            if(j >= wi[i]) {
                dpr[dp][i][j] = max(dpr[dp][i + 1][j - wi[i]] + vi[i],dpr[dp][i][j]);
            }
        }
    }
    for(int i = mid + 2; i <= r; i++) {
        for(int j = 0; j < M; j++) {
            dpl[dp][i][j] = dpl[dp][i - 1][j];
            if(j >= wi[i]) {
                dpl[dp][i][j] = max(dpl[dp][i - 1][j - wi[i]] + vi[i],dpl[dp][i][j]);
            }
        }
    }
    build(l,mid,dp + 1);
    build(mid + 1,r,dp + 1);
}
int query(int l,int r,int ll,int rr,int x,int p) {
    int mid = l + r >> 1;
    int ans = 0;
    if(mid >= ll && mid <= rr) {
        for(int i = 0; i <= p; i++) {
            ans = max(ans,dpr[x][ll][i] + dpl[x][rr][p - i]);
        }
        return ans;
    }
    if(mid > rr) ans = query(l,mid,ll,rr,x + 1,p);
    else ans = query(mid + 1,r,ll,rr,x + 1,p);
    return ans;
} 
void miss() {
    int n;
    cin >> n;                
    for(int i = 1; i <= n; i++) {
        cin >> wi[i];
    }
    for(int i = 1; i <= n; i++) {
        cin >> vi[i];
    }
    build(1,n,0);
    int q;
	cin >> q;
	int last = 0;
	while(q--){
		int xl,xr,xw;
		cin >> xl >> xr >> xw;
		xl = (xl+last)%n + 1;
		xr = (xr+last)%n + 1;
		xw = (xw+last)%10000 + 1;
		if(xl > xr)swap(xl,xr);
		if(xl == xr && xw >= wi[xl]) last = vi[xl];
        else last = query(1,n,xl,xr,0,xw);
        cout << last << endl;
	}
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    int T = 1;
    //cin >> T;
    while(T--) miss();
} 
posted on 2025-10-18 12:01  xiaowang524  阅读(8)  评论(0)    收藏  举报