ABC425题解

A. Sigma Cubes

code
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
	cin >> n;
	int ans = 0;
	for(int i = 1; i <= n; ++i){
		ans += ((i&1)?-1:1) * (i * i * i); 
	}
	cout << ans;
} 

B. Find Permutation 2

code
#include<bits/stdc++.h>
using namespace std;
const int NN = 1e4 + 8;
int n;
int a[NN],b[NN];
int main(){
	cin >> n;
	for(int i = 1; i <= n; ++i) cin >> a[i];
	for(int i = 1; i <= n; ++i)if(a[i] != -1){
		if(b[a[i]] == 0) b[a[i]] = 1;
		else{
			cout << "No";
			return 0;
		}
	}
	for(int i = 1,j = 1; i <= n; ++i){
		if(a[i] == -1){
			while(b[j]) ++j;
			a[i] = j;++j;
		}
	}
	cout << "Yes\n";
	for(int i = 1; i <= n; ++i) cout << a[i] << " ";
}

C. Rotate and Sum Query

记录偏移量 + 分讨

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 2e5 + 8;
int n,Q;
ll a[NN];
ll pre[NN];
int jum; 
int main(){
	cin >> n >> Q;
	for(int i = 1; i <= n; ++i){
		cin >> a[i];
		pre[i] = pre[i-1] + a[i];
	}
	while(Q--){
		int op;
		cin >> op;
		if(op == 1){
			int c;
			cin >> c; jum += c;
			jum %= n;
		}
		else{
			int l,r;
			cin >> l >> r;
			l += jum; r += jum;
			if(l <= n && r <= n) cout << pre[r] - pre[l-1] << "\n";
			else if(l <= n && r > n){
				r -= n;
				cout << pre[r] + pre[n] - pre[l-1] << "\n";
			}
			else if(l > n && r > n){
				l -= n; r -= n;
				cout << pre[r] - pre[l-1] << "\n"; 
			}
		}
	}
} 

D. Ulam-Warburton Automaton

跑一遍 bfs(不能每次扩展扫一遍全图,而是每次扩展找出新的可能被扩展的点)

code
#include<bits/stdc++.h>
using namespace std;
const int NN = 3e5 + 8;
int cnt,precnt;
int H,W;
int x_[4] = {0,0,1,-1};
int y_[4] = {1,-1,0,0};
vector<int> M[NN];
string s;
struct Node{
	int x,y;
};
queue<Node> Q,Q2,Q3;
void color(int x,int y){
	M[x][y] = 1;
	for(int i = 0; i < 4; ++i){
		int tx = x + x_[i], ty = y + y_[i];
		if(M[tx][ty] == 0 && tx != 0 && ty != 0 && tx <= H && ty <= W) Q2.push({tx,ty});
	}
}
bool Calc(int x,int y){
	int sum = 0;
	for(int i = 0; i < 4; ++i) sum += M[x+x_[i]][y+y_[i]]; 
	return sum == 1;
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> H >> W;
	M[0].resize(W+2);
	M[H+1].resize(W+2);
	for(int i = 1; i <= H; ++i){
		M[i].resize(W+2);
		cin >> s;
		for(int j = 0; j < W; ++j){
			if(s[j] == '#'){
				M[i][j+1] = 1;
			}
			else{
				M[i][j+1] = 0;
			}
		}
	}
	for(int i = 1; i <= H; ++i){
		for(int j = 1; j <= W; ++j){
			if(M[i][j] == 1){
				++cnt;
				color(i,j);
			}
		}
	}
	swap(Q,Q2);
	while(cnt != precnt){
		precnt = cnt;
		while(!Q.empty()){
			int x = Q.front().x,y = Q.front().y;Q.pop();
			if(Calc(x,y)){
				Q3.push({x,y});
			}
		}
		while(!Q3.empty()){
			int tx = Q3.front().x,ty = Q3.front().y;
			Q3.pop();
			color(tx,ty); ++cnt;
		}
		swap(Q,Q2);
	}
	cout << cnt;
}

E. Count Sequences 2

可以知道答案可以两种方法求解,计 \(sum = \sum a_i\)

我们的答案即为 \(\frac{sum!}{\prod (a_i!)}\),又因为模数不是质数,所以我们可以因式分解 \(i!\) 并且预处理

我们的答案还可以写成 \(\prod_{i=1}^n \binom {sum - \sum_{j=1}^{i-1}a_j}{a_i}\),对于这个式子,我们可以通过加法的递推公式预处理组合数。

code
#include<bits/stdc++.h>
using namespace std;
const int NN = 5e3 + 8,MM = 700;
typedef long long ll;
int T,M;
int n;
int a[NN],sum;
int prime[NN],cnt;
bool inp[NN];

int ans[MM];
int jcnum[NN][MM];
ll ksm(ll x,ll k){
	ll ans = 1;
	while(k){
		if(k&1) ans = ans * x % M;
		x = x * x % M;
		k >>= 1;
	}
	return ans;
}
void get(int x){
	int rx = x;
	for(int i = 1; i <= cnt; ++i){
		jcnum[rx][i] = jcnum[rx-1][i];
		while(x % prime[i] == 0){
			++jcnum[rx][i]; x /= prime[i];
		}
	}
}
void init(){
	for(int i = 2; i <= 5e3; ++i){
		if(!inp[i]){
			prime[++cnt] = i;
			for(int j = 2; j * i <= 5e3; ++j) inp[i*j] = 1;
		}
	}
	for(int i = 2; i <= 5e3; ++i) get(i);
}
void solve(){
	cin >> n;
	sum = 0;
	for(int i = 1; i <= n; ++i){
		cin >> a[i];
		sum += a[i];
		for(int j = 1; j <= cnt; ++j){
			ans[j] -= jcnum[a[i]][j];
		}
	}
	for(int i = 1; i <= cnt; ++i) ans[i] += jcnum[sum][i];
	ll res = 1;
	for(int i = 1; i <= cnt; ++i){
		res = res * ksm(prime[i],ans[i]) % M;
		ans[i] = 0;
	}
	cout << res << '\n';
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	init();
//	int st = clock();
//	for(int i = 1; i <= 5000; ++i) get(i);
//	int ed = clock();
//	cout << (double)((ed-st) * 1.0 / CLOCKS_PER_SEC) << endl;
	cin >> T >> M;
	while(T--){
		solve();
	}
}

F. Inserting Process

tag: 状压DP

\(N \leq 22\) 显然是一个状压 DP 的数据范围

然后就是我们可以发现我们只需要处理原串是类似于 \(aa\) 串再插入一个 \(a\),插在最前面,中间和末尾等价的情况。

这种情况,我们只把插入到最前面纳入贡献,状压的时候,就看我们插入的这个位置的前一位是不是和当前插入的这个字符相同即可

code
#include<bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
const int NN = (1 << 22) + 8;
int n;
string s;
int f[NN];
int main(){
	ios::sync_with_stdio(false),cin.tie(0);
	cin >> n;
	cin >> s;
	s = ' ' + s + ' ';
	f[0] = 1;
	for(int i = 1; i < (1<<n); ++i){
		int pre = 0,next = 0;
		for(int j = 0; j <= n; j = next){
			int k;
			for(k = j+1; k <= n; ++k){
				if(i >> (k-1) & 1){
					break;
				}
			}
			next = k;
			if(j == 0) continue;
			if(s[pre] != s[j]) f[i] += f[i ^ (1 << (j-1))];
			if(f[i] >= MOD) f[i] -= MOD;
			pre = j;
		}
	}
	cout << f[(1 << n) - 1] << '\n';
}

G. Sum of Min of XOR

tag:01trie

我们可以发现,如果说 \(M\) 的大小不大的话,我们可以很容易就直接用暴力的方法解决

我们又能够发现,需要的询问是连续的,我们深入探究可以知道有一些贡献可以重复进行计算。

我们只需要维护对于 01trie 每一个节点,该节点所代表的区间的数的所有答案之和即可,然后每一个节点的答案都可以轻易地通过子节点的答案分讨求出

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 2e5 + 8; 
ll n,m;
ll a[NN],ans[NN];

struct trie{
	int son[2];
	ll sum;
	#define son(x,y) tree[x].son[y] 
	#define ls(x) tree[x].son[0]
	#define rs(x) tree[x].son[1]
	#define sum(x) tree[x].sum
}tree[NN << 6];
int node_cnt = 1;
void build(ll x){
	int now = 1;//1号点的答案范围是 [0,2^32)  
	for(int i = 31; i >= 0; --i){
		int ts = (x >> i) & 1;
		int &v = son(now,ts);
		if(v == 0) v = ++node_cnt;
		now = v;
	}
}
void solve(int x,int dep){
	ll lans = 1e18, rans = 1e18;
	if(ls(x) != 0){
		solve(ls(x),dep-1);
		lans = sum(ls(x));
	}
	if(rs(x) != 0){
		solve(rs(x),dep-1);
		rans = sum(rs(x));
	}
	lans = min(lans, (1ll << (dep*2)) + rans);
	rans = min(rans, (1ll << (dep*2)) + lans);
	if(ls(x) == 0 && rs(x) == 0) lans = rans = 0;
	sum(x) = lans + rans;
}
void getans(){
	int x = 1;
	ll ans = 0,dep = 31;
	while(dep >= 0){
		int op = m >> dep & 1;
		if(op == 0){
			if(son(x,0) == 0){
				ans += (1ll << dep) * (m+1);
				x = son(x,1);
			}
			else x = son(x,0);
		}
		else{
			if(son(x,0) == 0) ans += (1ll << (dep*2)) + sum(son(x,1));
			else ans += sum(son(x,0));
			m -= 1 << dep;
			if(son(x,1) == 0){
				ans += (1ll << dep) * (m+1);
				x = son(x,0);
			}
			else x = son(x,1);
		}
		--dep; 
	}
	cout << ans;
}
int main(){
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> n >> m; --m;
	if(n == 0){
		cout << m*(m+1) / 2;return 0;
	}
	for(int i = 1; i <= n; ++i){
		cin >> a[i];
		build(a[i]);
	}
	solve(1,31);
//	cout << sum(1); 
	getans();
}
posted @ 2025-09-28 16:04  ricky_lin  阅读(37)  评论(0)    收藏  举报