【做题记录】HZOJ 多校-数论/多校-字符串/多校-图论Ⅲ

26. 数论 H. [arc137_d]Prefix XORs

对于普通的前缀和,有 \(S_i^{(k)}=\sum_{j=1}^{i}{i-j+k-1\choose k-1}a_j\),其中 \(S_i^{(k)}\) 表示 \(k\) 次前缀和后 \(a_i\) 的值(可以归纳证明)。

那么对于异或和,\(a_i\) 对第 \(k\) 次的答案有贡献的充要条件即为 \({n-i+k-1\choose k-1}\equiv1\pmod{2}\)。由卢卡斯定理可知它的充要条件又是 \((n-i)\mathrm{bitand}(k-1)=0\)。于是第 \(k\) 个答案即为:

\[\bigoplus_{i=1}^{n}a_i[(n-i)\subseteq\overline{(k-1)}] \]

高维前缀和即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=(1<<20)+5;
int n,m,a[maxn];
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[n-i];
	}
	for(int i=0;i<=19;i++){
		for(int S=0;S<1<<20;S++){
			if(S>>i&1){
				a[S]^=a[S^1<<i];
			}
		}
	}
	for(int i=0;i<m;i++){
		cout<<a[((1<<20)-1)^i]<<' ';
	}
	return 0;
}
}
int main(){return asbt::main();}

28. 数论 L. [THUPC 2023 初赛] 背包

注意到 \(V\) 很大,考虑先用某个 \(\frac{c_i}{v_i}\) 最大的物品填很多个,然后再进行 DP。具体的 DP 考虑同余最短路,设 \(\frac{c_i}{v_i}\) 最大的物品的 \(c_i=w,v_i=m\),则对于任何一个 \(m\) 剩余系中的点,在最长路径中都不会经过很多次,因为不如换成若干个 \((m,w)\) 更优。

考虑对于询问 \(V\),一个背包方案 \((V',C')\ (V'\equiv V\pmod{m})\) 对应的答案是什么。其实就是将剩下的部分全都用 \((m,w)\) 填充,即为:

\[C'+\left\lfloor\frac{V-V'}{m}\right\rfloor\times w\\[3mm] =\left\lfloor\frac{V}{m}\right\rfloor\times w+\left(C'-\left\lfloor\frac{V'}{m}\right\rfloor\times w\right) \]

因此对于每个剩余系我们要求最大的 \(C'-\lfloor\frac{V'}{m}\rfloor\times w\)。于是有转移:

\[f_{(u+v_i)\bmod m}\gets f_u+c_i-\left\lfloor\frac{u+v_i}{m}\right\rfloor\times w \]

然而这是最长路,不能用 dijkstra,spfa 是绝对不会用的。怎么办呢?有一种很强的转圈技术可以做到时间复杂度 \(O(nm)\)。简单来说,因为最长路径上不可能经过同一个点 \(2\) 次,所以对于 \(v_i\) 这个物品在图中形成的 \(\gcd(v_i,m)\) 个环,绕着每个环转两圈转移一遍即可。因为不会重复经过一个点,因此所有 \(P'\le m^2=10^{10}<V\),故有正确性。

Code
#include<bits/stdc++.h>
#define int long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=1e5+5,inf=1e18;
int n,q,v[55],c[55],f[maxn];
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>q;
	int m=1,w=0;
	for(int i=1;i<=n;i++){
		cin>>v[i]>>c[i];
		if(w*v[i]<m*c[i]){
			m=v[i],w=c[i];
		}
	}
	memset(f,-0x3f,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=__gcd(v[i],m)-1;~j;j--){
			for(int u=j,cnt=0;cnt<=1;cnt+=u==j){
				f[(u+v[i])%m]=max(f[(u+v[i])%m],f[u]+c[i]-(u+v[i])/m*w);
				u=(u+v[i])%m;
			}
		}
	}
	while(q--){
		int x;
		cin>>x;
		if(f[x%m]<=-inf){
			cout<<-1<<'\n';
		}else{
			cout<<f[x%m]+x/m*w<<'\n';
		}
	}
	return 0;
}
}
signed main(){return asbt::main();}

32. 字符串 A. 【模板】KMP

这又是啥

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=1e6+5;
int nxt[maxn];
string a,b;
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>a>>b;
	int n=a.size(),m=b.size();
	a=" "+a,b=" "+b;
	for(int i=2,j=0;i<=m;i++){
		while(j&&b[j+1]!=b[i]){
			j=nxt[j];
		}
		if(b[j+1]==b[i]){
			j++;
		}
		nxt[i]=j;
	}
	for(int i=1,j=0;i<=n;i++){
		while(j&&b[j+1]!=a[i]){
			j=nxt[j];
		}
		if(b[j+1]==a[i]){
			j++;
		}
		if(j==m){
			cout<<i-m+1<<'\n';
			j=nxt[j];
		}
	}
	for(int i=1;i<=m;i++){
		cout<<nxt[i]<<' ';
	}
	return 0;
}
}
signed main(){return asbt::main();}

33. 图论 G. 【模板】欧拉路径

这都是啥

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
using namespace std;
namespace asbt{
const int maxn=1e5+5;
int n,m,in[maxn],out[maxn],c[maxn];
vector<int> e[maxn],ans;
il void dfs(int u){
	for(int &i=c[u];i<e[u].size();){
		dfs(e[u][i++]);
	}
	ans.pb(u);
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1,u,v;i<=m;i++){
		cin>>u>>v;
		out[u]++,in[v]++;
		e[u].pb(v);
	}
	int s=0,t=0;
	bool flag=0;
	for(int i=1;i<=n;i++){
		sort(e[i].begin(),e[i].end());
		if(in[i]!=out[i]){
			flag=1;
		}
		if(in[i]+1==out[i]){
			if(s){
				cout<<"No";
				return 0;
			}
			s=i;
		}else if(in[i]==out[i]+1){
			if(t){
				cout<<"No";
				return 0;
			}
			t=i;
		}
	}
	if((!s||!t)&&flag){
		cout<<"No";
		return 0;
	}
	if(!flag){
		s=t=1;
	}
//	cout<<s<<' '<<t<<'\n';
//	cout<<s;
	dfs(s);
	for(int i=m;~i;i--){
		cout<<ans[i]<<' ';
	}
	return 0;
}
}
signed main(){return asbt::main();}

35. 数论 K. 牛场围栏

以最小的木料为同余最短路的模数,求出每个剩余系能凑出的最小的长度即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=3e3+5,inf=1e9;
int n,m,a[maxn],f[maxn];
bool vis[maxn];
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1,x;i<=n;i++){
		cin>>x;
		for(int j=0;j<=min(x-1,m);j++){
			vis[x-j]=1;
		}
	}
	int ma=0;
	for(int i=1;i<=3e3;i++){
		if(vis[i]){
			ma=i;
			break;
		}
	}
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	for(int i=1;i<=3e3;i++){
		if(!vis[i]){
			continue;
		}
		for(int j=__gcd(i,ma)-1;~j;j--){
			for(int u=j,cnt=0;cnt<=1;cnt+=u==j){
				f[(u+i)%ma]=min(f[(u+i)%ma],f[u]+i);
				u=(u+i)%ma;
			}
		}
	}
	int ans=-1;
	for(int i=0;i<ma;i++){
		ans=max(ans,f[i]-ma);
	}
	cout<<(ans>=inf?-1:ans);
	return 0;
}
}
signed main(){return asbt::main();}

36. 图论 D. [COCI2017-2018#5] Planinarenje

显然是二分图博弈虽然我咋不会,有如下结论:如果出发点一定在最大匹配上则先手必胜,否则后手必胜。于是先跑匈牙利,再在跑出的匹配上找出不一定在最大匹配上的点即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
using namespace std;
namespace asbt{
const int maxn=5e3+5;
int n,m,vis[maxn],mch[maxn];
bool f[maxn];
vector<int> e[maxn];
il bool dfs1(int u,int tag){
	for(int v:e[u]){
		if(vis[v]!=tag){
			vis[v]=tag;
			if(!mch[v]||dfs1(mch[v],tag)){
				mch[v]=u;
				return 1;
			}
		}
	}
	return 0;
}
il void dfs2(int u){
	f[u]=1;
	for(int v:e[u]){
		if(~vis[v]){
			vis[v]=-1;
			dfs2(mch[v]);
		}
	}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1,u,v;i<=m;i++){
		cin>>u>>v;
		e[u].pb(v);
	}
	for(int i=1;i<=n;i++){
		if(!dfs1(i,i)){
			dfs2(i);
		}
	}
	for(int i=1;i<=n;i++){
		cout<<(f[i]?"Mirko":"Slavko")<<'\n';
	}
	return 0;
}
}
signed main(){return asbt::main();}

37. 字符串 E. Anthem of Berland

考虑 DP。设 \(f_i\) 表示 \(s_{1\sim i}\) 最多匹配多少个 \(t\)。考虑转移,如果 \(s_{i-m+1\sim i}\) 能直接与 \(t\) 匹配,显然可以转移。但并不完全,因为 \(t\) 可以重叠,因此需要跳失配数组。但此时又出大问题,我们不能保证枚举到的失配指针能在上一个位置匹配上。于是我们再设 \(g_i\) 表示强制 \(i\) 位置匹配的最大值即可。时间复杂度 \(O(nm)\)

尝试带空格马蜂,这也太困难了吧

Code
#include <bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt {
const int maxn = 1e5 + 5;
int n, m, nxt[maxn], f[maxn], g[maxn];
string s, t;
il bool check(int p) {
	for(int i = 1; i <= m; i++) {
		if(s[p - i + 1] != t[m - i + 1] && s[p - i + 1] != '?') {
			return 0;
		}
	}
	return 1;
}
int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> s >> t;
	n = s.size(), m = t.size(), s = " " + s, t = " " + t;
	for(int i = 2, j = 0; i <= m; i++) {
		while(j && t[j + 1] != t[i]) {
			j = nxt[j];
		}
		if(t[j + 1] == t[i]) {
			j++;
		}
		nxt[i] = j;
	}
	for(int i = m; i <= n; i++) {
		f[i] = f[i - 1];
		if(!check(i)) {
			continue;
		}
		g[i] = f[i - m] + 1;
		for(int j = nxt[m]; j; j = nxt[j]) {
			g[i] = max(g[i], g[i - m + j] + 1);
		}
		f[i] = max(f[i], g[i]);
	}
	cout << f[n];
	return 0;
}
}
signed main() {return asbt::main();}

39. 图论 H. Melody

对于每个声音连边 \(v_i\longleftrightarrow p_i\),跑个欧拉路径即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
#define pk pop_back
#define lwrb lower_bound
#define pii pair<int,int>
#define mp make_pair
#define fir first
#define sec second
using namespace std;
namespace asbt{
const int maxn=4e5+5;
int T,n,a[maxn],b[maxn],la[maxn],lb[maxn],deg[maxn],fa[maxn];
bool vis[maxn];
vector<pii> e[maxn];
il int find(int x){
	return x!=fa[x]?fa[x]=find(fa[x]):x;
}
il void dfs(int u){
	while(e[u].size()){
		int v=e[u].back().fir,t=e[u].back().sec;
		e[u].pk();
		if(e[v].size()&&!vis[t]){
			vis[t]=1;
			dfs(v);
			cout<<t<<' ';
		}
	}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>T;
	while(T--){
		cin>>n;
		int ta=0,tb=0;
		for(int i=1;i<=n;i++){
			cin>>a[i]>>b[i];
			la[++ta]=a[i];
			lb[++tb]=b[i];
			vis[i]=0;
		}
		sort(la+1,la+ta+1);
		sort(lb+1,lb+tb+1);
		ta=unique(la+1,la+ta+1)-la-1;
		tb=unique(lb+1,lb+tb+1)-lb-1;
		for(int i=1;i<=ta+tb;i++){
			deg[i]=0,fa[i]=i;
			e[i].clear();
		}
		for(int i=1;i<=n;i++){
			a[i]=lwrb(la+1,la+ta+1,a[i])-la;
			b[i]=lwrb(lb+1,lb+tb+1,b[i])-lb+ta;
			deg[a[i]]++,deg[b[i]]++;
			fa[find(a[i])]=find(b[i]);
			e[a[i]].pb(mp(b[i],i));
			e[b[i]].pb(mp(a[i],i));
		}
		int s=0,t=0;
		bool flag=0;
		for(int i=1;i<=ta+tb;i++){
			if(find(i)==i){
				if(flag){
					cout<<"No\n";
					goto togo;
				}
				flag=1;
			}
			if(deg[i]&1){
				if(!s){
					s=i;
				}else if(!t){
					t=i;
				}else{
					cout<<"no\n";
					goto togo;
				}
			}
		}
		if(!s&&!t){
			s=t=1;
		}else if(!s||!t){
			cout<<"NO\n";
			goto togo;
		}
		cout<<"YES\n";
		dfs(s);
		cout<<'\n';
		togo:;
	}
	return 0;
}
}
signed main(){return asbt::main();}

40. 数论 Q. Koxia and Number Theory

首先不能有相同的数。

如果有四个数形如 \(2p_0,2q_0,2p_1+1,2q_1+1\),则必然无解,因为 \(x\) 取奇数/偶数都不行。

进一步推广,如果对于质数 \(P\),其每个剩余系中都有至少两个数,则必然无解。否则,设模 \(P\) 等于 \(k\) 的剩余系中只有一个/零个数,我们可以令 \(x\equiv-k\pmod{P}\),这样所有 \(a_i+x\) 必然没有 \(P\) 这个公因子。由 crt 知必然有解。于是我们枚举 \(n\) 以内的所有质数判断一遍即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
int T,n,cnt[105][105];
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>T;
	while(T--){
		for(int i:p){
			for(int j=0;j<i;j++){
				cnt[i][j]=0;
			}
		}
		cin>>n;
		set<ll> st;
		bool flag=0;
		for(int i=1;i<=n;i++){
			ll x;
			cin>>x;
			if(flag){
				continue;
			}
//			cout<<st.count(x)<<'\n';
			if(st.count(x)){
				cout<<"NO\n";
				flag=1;
			}
			st.insert(x);
			for(int j:p){
				cnt[j][x%j]++;
			}
		}
		if(flag){
			goto togo1;
		}
		for(int i:p){
			for(int j=0;j<i;j++){
				if(cnt[i][j]<2){
					goto togo2;
				}
			}
			cout<<"NO\n";
			goto togo1;
			togo2:;
		}
		cout<<"YES\n";
		togo1:;
	}
	return 0;
}
}
int main(){return asbt::main();}
/*
5
3
4 2 3
3
3 2 4
3
3 5 3
3
5 5 2
3
5 2 2
*/
posted @ 2025-11-23 20:23  zhangxy__hp  阅读(26)  评论(0)    收藏  举报