牛客2025多校 R1

牛客2025多校 R1

E:
题目大意:
image-20250716191159304

void solve(){
	LL a,b;
	cin>>a>>b;
	LL d=abs(b*b-a*a);
	if (d<=8){
		if (d==3) cout<<1<<endl;
		else if (d==5) cout<<2<<endl;
		else if (d==7) cout<<3<<endl;
		else if (d==8) cout<<4<<endl;
		return ;
	}
	LL ans=d/2-1;
	ans+=d/4-1;
	cout<<ans+d%2<<endl;
}

注意到这样一个性质:能被表示成两数的平方差的数 \(x\) ,当且仅当 \(x\) 为大于 \(1\) 的奇数以及大于 \(4\)\(4\) 的整倍数

简单证明:设一个正整数为 \(k\) ,另外一个正整数为 \(k+d\) ,则 \(x=(k+d)^2-k^ 2\)

\(d\)\(1\) 时:\(x=2k+1\),当 \(d\)\(2\) 时:\(x=4k+4\) ,当 \(d\)\(3\) 时:\(x=6k+9\) 以此类推

那么对于所有 \(d\) 的取值都能够将 \(x\) 表示为两类:\(x=2m+1,x=4m+4\) 其中 \(m>0\)

G:
题目大意:
image-20250716192024411

void solve(){
	int n,q;
	cin>>n>>q;
	string S;
	cin>>S;
	while (q--){
		string s;
		int a;
		cin>>s>>a;
		LL tsum=0;
		LL ans=0;
		for (int i=0;i<=min((int)s.size()-1,n-a);i++){
			if (S[i+a-1]==s[i])
				tsum++;
			else{
				ans+=tsum*(tsum+1)/2;
				tsum=0;
			}
		}
		ans+=tsum*(tsum+1)/2;
		cout<<ans<<endl;
	}
}

遍历匹配区间,找到最长的系统区间后计算子区间个数

L:

题目大意:

image-20250716192224485

#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

LL a[200010];

void solve(){
	LL n,q;
	cin>>n>>q;
	LL idx=0;
	for (int i=1;i<=n;i++) cin>>a[i];
	tree<pair<LL,LL>,null_type,less<pair<LL,LL>>,rb_tree_tag,tree_order_statistics_node_update> bt;
	for (int i=1;i<=n;i++) bt.insert({a[i],++idx});
	while (q--){
		LL p,v;
		cin>>p>>v;
		bt.erase(bt.upper_bound({a[p],0}));
		a[p]+=v;
		bt.insert({a[p],++idx});
		auto pos=bt.find_by_order((n+1)/2);
		cout<<bt.order_of_key({pos->first,0})<<endl;
	}
}

本质上是计算这些数字中小于等于中位数的元素个数,原本写的线段树和树状数组都被 T 掉了

用pbds的红黑树可以方便的维护出中位数的值,然后直接计算个数即可

K:
题目大意:

image-20250716192941782

vector<int> e[N];
bool vis[N][4];
int dp[N][4];
int cnt;

void dfs(int x,int indoor){
	if (vis[x][(indoor+1)%e[x].size()]) return;
	 int nextnode=e[x][(indoor+1)%e[x].size()];
	 for (int i=0;i<e[nextnode].size();i++){
	 	if (e[nextnode][i]==x){
	 		if (!vis[nextnode][i]) cnt++;
	 		vis[x][(indoor+1)%e[x].size()]=1;
	 		dfs(nextnode,i);
	 		vis[x][(indoor+1)%e[x].size()]=0;
	 	}
	 }
	 dp[x][indoor]=cnt;
}

void solve(){
	int n;
	cin>>n;
	for (int i=1;i<=n;i++){
		int d;
		cin>>d;
		for (int j=1;j<=d;j++){
			int v;
			cin>>v;
			e[i].push_back(v);
		}
	}
	for (int i=1;i<=n;i++){
		cnt=0;
		if (dp[i][e[i].size()-1]==0)
			dfs(i,e[i].size()-1);
		cout<<dp[i][e[i].size()-1]<<endl;
	}
}

记忆化搜索,\(dp_{i,j}\) 表示第 \(i\) 个房间从 \(j\) 号门进来经过的不同走廊个数

足够长的时间后,经过的节点会形成一个环,环上的点可以 DFS 一次维护出来

开静态变量 cnt 表示当前 DFS 过程中在环上的点能经过的不同走廊个数,并且当且仅当下一个走到的房间之前没有被走过才会增加答案记录的走廊个数

posted @ 2025-07-19 18:52  才瓯  阅读(3)  评论(0)    收藏  举报