CSP-S模拟31

CSP-S模拟31

A. 远征 (expedition)

简单题,直接大力 \(O(nV)\) 预处理 对于每个数每个位置 记录这个数下一个会被更改的位置。

查询直接跳即可,复杂度是 \(O(\log V)\)

Code:

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
	int x=0,c=getchar_unlocked();
	for(;c>'9'||c<'0';c=getchar_unlocked());
	for(;c>='0'&&c<='9';c=getchar_unlocked())
		x=(x<<1)+(x<<3)+(c^48);
	return x;
}

int n;
const int N=5e4+5;
unsigned short nxt[1025][N];
int a[N],b[N];

void init()
{
	for(int col=1;col<1024;col++)
	for(int i=n,last=n+1;i>=1;i--)
	{
		nxt[col][i]=last;
		if((col|a[i])==col) last=i;
	}
}

signed main()
{
	//expedition
	freopen("expedition.in","r",stdin);
	freopen("expedition.out","w",stdout);

	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) b[i]=read();

	init();

	long long Q=read(),anss=0;
	while(Q--)
	{
		int l=read(),r=read(),x=read();
		long long ans=0;
		if((x|a[l])==x) ans+=b[l],x^=a[l];

		l=nxt[x][l];
		while(l<=r&&x)
		{
			ans+=b[l];
			x^=a[l];
			l=nxt[x][l];
		}
		anss^=ans;
	}
	cout<<anss;

	return 0;
}

B. 传送 (teleport)

以为是拦路虎,没想到是水。

显然题目的限制 \(3\) 是废话。

先特判 \(u=v\) (\(ans=0\)) 和 \(u,v\) 不在一个集合内 (\(ans=-1\)) 的情况。

先把题目中给出的四元环(偶环)画出来,发现答案至多为 \(2\)

再手模一个三元环(奇环),发现是强连通的,再尝试加边,发现新图仍强连通。五元环同理,也是强连通的。

得到若一个连通块包含奇环,则答案为 \(1\)

若无奇环,则如果 \(u \to v\) 路径长为偶,则答案为 \(2\)。反之答案为 \(1\)

现在关键问题转化为如何在 \(O(n)\) 复杂度内判断该连通块是否有奇环。(当然你可以直接黑白染色判断。)

我们以惊人的注意力发现(当然你也可以从 \(s=1\) 的部分分得到启发),我们在每个连通块内任选一点跑 bfs(设为 \(S\)),记录 \(S\) 到该连通块内的每一个点 \(x\) 的路径 (\(S \to x\)) 长是否可以是偶数 / 奇数。发现若该连通块内存在奇环,则 \(S \to x\) 的路径既有奇长又有偶长。

对于无奇环,发现若 \(u \to v\) 路径长为偶 (\(ans=2\)),则 \(S \to u\)\(S \to v\) 路径长奇偶性相同。反之 \(ans=1\)

做完了。

Code:

#include<bits/stdc++.h>
// #define int long long

// #define getchar_unlocked getchar
// #define putchar_unlocked putchar

using namespace std;

inline int read()
{
	int x=0,c=getchar_unlocked();
	for(;c>'9'||c<'0';c=getchar_unlocked());
	for(;c>='0'&&c<='9';c=getchar_unlocked())
		x=(x<<1)+(x<<3)+(c^48);
	return x;
}

// #ifndef ONLINE_JUDGE
// #define ONLINE_JUDGE
// #endif

const int N=1<<20;
int n,m;
vector<int> E[1<<20];
int fa[1<<20];
int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}

bool vis[N][2];
struct Node{
	int p,cnt;
};

void bfs(int S)
{
	queue<Node> q;
	q.push({S,0});
	vis[S][0]=1;
	while(q.size())
	{
		Node nw=q.front();
		q.pop();
		nw.cnt^=1;
		// cerr<<nw.p<<" "<<nw.cnt<<"\n";
		for(int to:E[nw.p])
		{
			if(vis[to][nw.cnt]) continue;
			vis[to][nw.cnt]=1;
			q.push({to,nw.cnt});
		}
	}
}

int strong[N];

signed main()
{
	// teleport
	// #ifndef ONLINE_JUDGE
	freopen("teleport.in","r",stdin);
	freopen("teleport.out","w",stdout);
	// #endif

	int T=read();

	n=read();
	m=read();
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		int fx=find(u),fy=find(v);
		E[u].push_back(v);
		E[v].push_back(u);
		if(fx==fy) continue;
		fa[fx]=fy;
	}
	for(int i=1;i<=n;i++)
	if(vis[i][0]==0&&vis[i][1]==0) bfs(i);

	for(int i=1;i<=n;i++)
	if(vis[i][0]&&vis[i][1]) strong[find(i)]=1;

	int Q=read();

	while(Q--)
	{
		int u=read(),v=read();
		if(u==v) { putchar_unlocked('0'); }
		else if(find(u)!=find(v)) { putchar_unlocked('-'); putchar_unlocked('1'); }
		else if(strong[find(u)]) { putchar_unlocked('1'); }
		else putchar_unlocked((vis[u][0]^vis[v][0])?('1'):('2'));
		putchar_unlocked('\n');
	}

	return 0;
}

C. 先辈 (anc)

小 Y 定义野兽串是 \(t=114514\)

\(|S|\) 为字符串 \(S\) 的长度。

我们显然有一个 \(O(26^3|S|)\) 的做法,枚举当 \(1,4,5\) 的字符,统计答案。做 nxt 数组优化可做到 \(O(26^3\frac{3|S|}{26})\)。但还是过不了。

具体,设 \(dp[i]\) 表示长度为 \(i\) 一共有多少种情况。
转移也非常显然。
显然 \(dp\) 数组只需要开到 \(7\) 就够了。

考虑发现一些性质。

发现 \(5\) 出现至多 \(1\) 次。考虑不枚举 \(5\) 表示的字符,只枚举 \(1\)\(4\)。只限制 \(5\) 不能和 \(1,4\) 相同即可。

转移同上,只修改 \(dp[4]\) 的转移方程。

如果 TLE,减少你的取模量。

Code:

#include<bits/stdc++.h>
// #define int long long

using namespace std;

const int N=5e5+5;
int totans=0;
int dp[6];

int n;
string s;
short c[N];

const int mod=114514;
int cntt=0;
int nxt[N][26];
int poss[N];
int O=0;

bool isappear[26];

void init()
{
	n=s.size();
	for(int col=0;col<26;col++)
	for(int i=n,last=n+1;i>=0;i--)
	{
		nxt[i][col]=last;
		if(col+'a'==s[i-1]) last=i;
	}

	for(int i=1;i<=n;i++) c[i]=s[i-1]-'a',isappear[c[i]]=1;
}

void dodp(int x,int y)
{
	int nwwwww=totans;
	memset(dp,0,sizeof(dp));
	dp[0]=1;
	for(int i=0;i<cntt;i++)
	{
		// cout<<poss[i]<<" "<<c[poss[i]]<<"\n";
		// O++;
		long long dt=0;
		if(i) dt=poss[i]-poss[i-1]-1;
		dp[4]=(dp[4]+dp[3]*dt)%mod;
		// dp[4]%=mod;
		// totans=(totans+dp[5]*dt)%mod;
		if(c[poss[i]]==x) 
		{
			dp[5]+=dp[4];
			dp[2]+=dp[1];
			dp[1]+=dp[0];

			dp[1]%=mod;
			dp[2]%=mod;
			dp[5]%=mod;
		}
		if(c[poss[i]]==y)
		{
			dp[3]+=dp[2];
			totans+=dp[5];

			dp[3]%=mod;
			totans%=mod;
		}

		// for(int j=1;j<=5;j++) cout<<"dp["<<j<<"]="<<dp[j]<<"\n";
		// cout<<"\n";
	}
	// cout<<"\n";
	// cout<<x+1<<" "<<y+1<<" "<<-(nwwwww-totans)<<"\n\n";
	// // totans=(totans+dp[5]*(n-poss[cntt-1]))%mod;
}

// #define min(a,b,c) a<b&&a<c?a:(b<c?b:c)
// #define max(a,b,c) a>b&&a>c?a:(b>c?b:c)

void init(int x,int y)
{
	if(!isappear[x]) return;
	if(!isappear[y]) return;
	// if(!isappear[z]) return;
	int i=0;
	poss[0]=min(nxt[0][x],nxt[0][y]);
	while(poss[i]<=n)
	{
		// O++;
		// poss[i+1]=poss[i]+26;
		poss[i+1]=min(nxt[poss[i]][x],nxt[poss[i]][y]);
		i++;
	}
	cntt=i;
	dodp(x,y);
	dodp(y,x);
	// for(int j=0;j<cntt;j++) poss[j]=c[poss[j]];

	// dodp(x,y,z);
	// dodp(x,z,y);
	// dodp(y,x,z);
	// dodp(y,z,x);
	// dodp(z,x,y);
	// dodp(z,y,x);
}

/*

void init(int a,int b,int c)
{
	int i=0;
	poss[0]=min({nxt[0][a],nxt[0][b],nxt[0][c]});
	int last=poss[i];
	while(last<=n)
	{
		last=min({nxt[last][a],nxt[last][b],nxt[last][c]});
		poss[i+1]=last;
		i++;
	}
}

*/

signed main()
{
	// ios::sync_with_stdio(0);
	freopen("anc.in","r",stdin);
	freopen("anc.out","w",stdout);

	cin>>s;
	init();

	for(int a=0;a<26;a++)
	for(int b=a+1;b<26;b++)
	init(a,b);

	cout<<totans<<"\n";
	// cerr<<"O="<<O<<"\n";
	
	// #ifndef ONLINE_JUDGE
	// #endif
	//mt19937_64 myrand(time(0));
	return 0;
}

D. 矩阵 (matrix)

数论分块。

Code:

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar()                                                              \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)     \
	? EOF                                                                 \
	: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

int n,k;
void solve()
{
	int ans=0;
	while(n)
	{
		int w=n/k;
		int ww=w+1;
		int kk=n/ww;
		int t=k-kk;
		ans+=w*(t*(n-w+n-w*t)/2);
		n-=w*t;
		k=kk;
	}
	cout<<ans<<"\n";
}

signed main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	
	scanf("%lld%lld",&n,&k);
	if(k>=n)
	{
		cout<<(n*(n-1))/2;
		return 0;
	}
	solve();
	return 0;
}




posted @ 2025-10-14 22:12  Wy_x  阅读(22)  评论(1)    收藏  举报