7.30 模拟赛总结

做题过程

开场 20 分钟做完第一题,测完大样例再造了组有空格的数据就没管了。接着是第二题,一眼 dp,然后我写了递推,花了两个小时调。此时比赛还剩 1 小时,思考第三题,第三题写了暴力,dfs \([l, r]\) 中的每一个 \(x_i\)。第四题啥都没写,剩下0.5h 罚座。

题目解法

A 题可以枚举每个字符串,再枚举每一个长度为二的区间,将其替换为 out ans,看是否可以匹配。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
map<string,int> mp;
string s[105];
int main(){
	freopen("judge.in","r",stdin);
	freopen("judge.out","w",stdout);
	int n,ans=0;
	cin>>n;
	getchar();
	for(int i=1;i<=n;i++){
		getline(cin,s[i]);
		for(int j=0;j<s[i].size();j++){
			if('A'<=s[i][j]&&s[i][j]<='Z') s[i][j]=s[i][j]-'A'+'a'; 
		}
		mp[s[i]]++;
	}
	for(int i=1;i<=n;i++){
		for(int l=0,r=1;r<s[i].size();l++,r++){
			if(s[i].substr(l,2)!="in") continue;
			string s1=s[i].substr(0,l)+"out"+s[i].substr(r+1,s[i].size()-2-l);
			string s2=s[i].substr(0,l)+"ans"+s[i].substr(r+1,s[i].size()-2-l);
			ans+=mp[s1]+mp[s2];
		}
	}
	cout<<ans;
	return 0;
}

B 题显然有 \(dp_{i,j,k,l}=x\) 表示前 \(i\) 个回合,有 \(j\) 的人,\(k\) 的电力,\(l\) 的石油,最多能有 \(x\) 的产品。考虑交换 \(x\)\(k\)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=15,lim=400;
int p[N],g[N],e[N],h[N];
int f[45][15][405][405];	
int n,m,H,task,ans;
void dfs(int t,int hh,int pp,int gg,int ee){
	if(f[t][hh][ee][gg]<pp) f[t][hh][ee][gg]=pp;
	else return;
	ans=max(ans,ee);
	if(t>m) return;
	for(int i=1;i<=n;i++){
		if(hh+h[i]>=0&&pp+p[i]>=0&&gg+g[i]>=0&&ee+e[i]>=0) dfs(t+1,hh+h[i],pp+p[i],gg+g[i],ee+e[i]);
	}
}
int main(){
	freopen("grid.in","r",stdin);
	freopen("grid.out","w",stdout);
	scanf("%d%d%d%d",&n,&m,&H,&task);
	for(int i=1;i<=n;i++) scanf("%d%d%d%d",&h[i],&p[i],&g[i],&e[i]);
	memset(f,-1,sizeof f);
	dfs(1,H,0,0,0);
	printf("%d",ans);
	return 0;
}

C 题根据裴蜀定理,有 \(ax + by = c\) 的有解情况当且仅当 \(\gcd(a,b) | c\),扩展到多个数,有 \(a_1x_1 + a_2x_2 + \dots + a_nx_n = c\) 有解当且仅当 \(\gcd(a_1, a_2, \dots, a_n) | c\),因此得到本题询问的答案为 \(\lfloor\frac{s}{\gcd(a_1, a_2, \dots, a_n)}\rfloor\)。线段树维护即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m;
ll a[N],seg[N<<2];
void push_up(int rt){
	seg[rt]=__gcd(seg[rt<<1],seg[(rt<<1)|1]);
}
void build(int rt,int l,int r){
	if(l==r){
		seg[rt]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build((rt<<1)|1,mid+1,r);
	push_up(rt);
}
void modify(int rt,int l,int r,int pos,ll val){
	if(l==r){
		seg[rt]=val;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) modify(rt<<1,l,mid,pos,val);
	else modify((rt<<1)|1,mid+1,r,pos,val);
	push_up(rt);
}
ll ask(int rt,int l,int r,int L,int R){
	if(L<=l&&r<=R) return seg[rt];
	int mid=(l+r)>>1;
	ll gcd=-1;
	if(L<=mid) gcd=ask(rt<<1,l,mid,L,R);
	if(mid<R){
		ll tmp=ask((rt<<1)|1,mid+1,r,L,R);
		if(~gcd) gcd=__gcd(gcd,tmp);
		else gcd=tmp;
	}
	return gcd;
}
void solve(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	memset(seg,0,sizeof seg);
	build(1,1,n);
	for(int op;m--;){
		scanf("%d",&op);
		if(op==1){
			int i;
			ll v;
			scanf("%d%lld",&i,&v);
			modify(1,1,n,i,v);
		}
		else{
			int l,r;
			ll s;
			scanf("%d%d%lld",&l,&r,&s);
			printf("%lld\n",s/ask(1,1,n,l,r));
		}
	}
}
int main(){
	 freopen("equation.in","r",stdin); freopen("equation.out","w",stdout);
	int T,task;
	scanf("%d%d",&T,&task);
	while(T--) solve();
	return 0;
}

D 题我们对每个线路暴力建边,边数 \(p^{2}m\) 条,点数 \(n\) 个,用 spfa 求最长路,理论最坏复杂度是 \(n^{2}p^{2}m\),不过这题没卡 spfa。

顺便说一句,在段凡丁的论文里,spfa 的复杂度是 \(\mathcal{O}(m)\) 的。虽然段凡丁错了,但是在大部分情况下,spfa 复杂度的确只在 \(\mathcal{O}(m)\) 左右。

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

using namespace std;
const int N=2e3+5;
int x[N],y[N],h[N],n,m;
ll dis[N];
bool in[N];
vector<pair<int,ll>> e[N];
ll calc(int x1,int y1,int x2,int y2){
	return ceil(sqrt(1ll*(x1-x2)*(x1-x2)+1ll*(y1-y2)*(y1-y2)));
}
int main(){
	freopen("metro.in","r",stdin);
	freopen("metro.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++) scanf("%d%d%d",&x[i],&y[i],&h[i]);
	for(int i=1; i<=m; i++){
		int p;
		scanf("%d",&p);
		vector<int> v;
		for(int j=0;j<p;j++){
			int b,las=0;
			scanf("%d",&b);
			v.push_back(b);
			for(int i=v.size()-2;i>=0;i--){
				e[v[i]].push_back({b,(las-=calc(x[v[i]],y[v[i]],x[v[i+1]],y[v[i+1]]))});
			}
		}
	}
	for(int i=1; i<=n; i++){
		memset(dis,0xc0,sizeof dis);
		memset(in,0,sizeof in);
		queue<int> q;
		q.push(i);
		in[i]=1;
		dis[i]=h[i];
		while(!q.empty()){
			int u=q.front();
			q.pop();
			in[u]=0;
			for(auto it:e[u]){
				int v=it.first;
				ll w=it.second+h[v];
				if(dis[v]<dis[u]+w){
					dis[v]=dis[u]+w;
					if(!in[v]){
						q.push(v);
						in[v]=1;
					}
				}
			}
		}
		for(int j=1; j<=n; j++){
			printf("%lld ",dis[j]);
		}
		printf("\n");
	}
	return 0;
}

反思总结

第一题做的没什么问题。

第二题花的时间太多了,在决策用记忆化搜索还是递推上不是很好,调试的时候也没想清楚细节,虽然最后是写对了,但是常数太大导致只拿了 60 分。

第三题是真的没思路,我写了个搜索,时间复杂度 \(\mathcal{O}(S^{r-l+1})\),一分没拿找。

第四题题都没读懂,给的时间太少了,没时间写部分分。

总结下来就是第二题花的时间太长了,导致第三题没有仔细想,第四题没读题。

posted @ 2025-08-01 20:21  sapo1o  阅读(30)  评论(0)    收藏  举报