2026 · CSP-S · 二十连测 · 模拟五题解

T1

最直接的做法就是直接去算每一个字符的个数。

显然,可以双指针优化。

代码

点击查看代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
int n,k,g;
int a[maxn];
int cnt[maxn],minn[maxn],b[maxn],q[maxn];
signed main()
{
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>k>>g;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=g;i++)
	{
		cin>>b[i]>>q[i];
		minn[b[i]]=q[i];
	}
	int l=g,r=0;
	int ans=inf;
	for(int i=1;i<=n;i++)
	{
		if(i!=1)
		{
			cnt[a[i-1]]--;
			if(cnt[a[i-1]]<minn[a[i-1]]) l++;
		}
		while(r<=n&&l)
		{
			r++;
			cnt[a[r]]++;
			if(cnt[a[r]]==minn[a[r]]) l--;
		}
		if(r<=n) ans=min(ans,r-i+1);
	}
	if(ans==inf) cout<<"impossible";
	else cout<<ans;
	return 0;
}

T2

一般这种贡献题都考虑拆贡献。

注意到贡献可以被拆为:\(x(1-y)(1-z)\) 用高维前缀和优化即可

代码

点击查看代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=20+5;
int n,k,ans,cnt,mp[maxn][maxn][maxn];
signed main()
{
	freopen("hunt.in","r",stdin);
	freopen("hunt.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>k;
    for(int i=1;i<=k;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        x--,y--,z--;
        mp[x][min(y,z)][max(y,z)]++;
    }
    int m=(1<<n)-1;
    for(int i=0;i<=m;i++)
    {
        int sum=0;
        for(int j=0;j<n;j++)
        {
            if((i&(1<<j))==0) continue; 
            for(int k=0;k<n;k++)
            {
                if((i&(1<<k))==(1<<k)) continue;
                for(int l=k+1;l<n;l++) 
                {
                    if((i&(1<<l))==(1<<l)) continue;
                    sum+=mp[j][k][l];
                }
            }
        }
        if(sum>ans) ans=sum,cnt=0;
        if(sum==ans) cnt++;
    }
    cout<<ans<<" "<<cnt;
    return 0;
}

T3

注意到矩形大小已经固定。但是整个坐标系的大小很大。所以我们可以考虑拆,每一个点所在的位置以及它的贡献都可以通过扫描线的方式处理出来。

直接用扫描线即可。

代码

点击查看代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1e5+5,len=1e9;
int n,h,w;
struct node
{
	int x,y,w;
}a[maxn];
int rt,cnt;
struct Tree
{
	int ls,rs,val,lazy;
}tree[maxn*100];
void update(int &x,int l,int r,int left,int right,int p)
{
	if(!x) x=++cnt;
	right=min(right,len);
	if(left<=l&&r<=right)
	{
		tree[x].val+=p;tree[x].lazy+=p;
		return;
	}
	int mid=l+r>>1;
	if(mid>=left) update(tree[x].ls,l,mid,left,right,p);
	if(mid<right) update(tree[x].rs,mid+1,r,left,right,p);
	tree[x].val=max(tree[tree[x].ls].val,tree[tree[x].rs].val)+tree[x].lazy;
}
bool cmp(node a,node b)
{
	return a.x<b.x;
}
signed main()
{
	freopen("clear.in","r",stdin);
	freopen("clear.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>h>>w;
	for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y>>a[i].w;
	sort(a+1,a+1+n,cmp);
	int p=1,ans=0;
	for(int i=1;i<=n;i++)
	{
		while(p<i&&a[i].x-a[p].x+1>h) update(rt,0,len,a[p].y,a[p].y+w-1,-a[p].w),++p;
		update(rt,0,len,a[i].y,a[i].y+w-1,a[i].w);
		ans=max(ans,tree[rt].val);
	}
	cout<<ans;
	return 0;
}

T4

其实我们会发现,所谓要进行相一个格子的运动,其实你可以朝任一个方向走到。然后再回来,因为在你一开始的地方已经生成了个冰块了,所以说你可以做到只移动一步的方法。

但是我们会注意到,这样子的方法会生成两个冰块。而且通过手玩一些数据可以发现很多。不合法的情况,都是因为走了回头路而诞生的,而不走回头路,他也有合法解

所以我们可以得到走回头路,一定不优

所以我们可以直接考虑不走回头路的情况即可

代码

点击查看代码
#include<bits/stdc++.h>
//#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1005;
char s[maxn][maxn];
int R[maxn][maxn],L[maxn][maxn],U[maxn][maxn],D[maxn][maxn],dis[maxn*maxn],vis[maxn*maxn][5];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1},n,m,to[maxn * maxn][4];
vector<pair<int,int> > g[maxn * maxn];
const int inf = 1e9;
void add(int u,int v,int w)
{
	g[u].push_back({v,w});
//	g[v].push_back({u,w});
}
int id(int x,int y)
{
	return m*(x-1)+y;
}
int in()
{
	int x,y;cin>>x>>y;
	return id(x,y);
}
signed main()
{
	freopen("skate.in","r",stdin); 
	freopen("skate.out","w",stdout); 
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>s[i][j];
	int ss=in(),t=in();
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) L[i][j]=(s[i][j-1]!='#'?L[i][j-1]:j);
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) U[i][j]=(s[i-1][j]!='#'?U[i-1][j]:i);
	for(int i=n;i>=1;i--) for(int j=m;j>=1;j--) R[i][j]=(s[i][j+1]!='#'?R[i][j+1]:j);
	for(int i=n;i>=1;i--) for(int j=m;j>=1;j--) D[i][j]=(s[i+1][j]!='#'?D[i+1][j]:i);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(s[i][j]!='#')
			{
				if(s[i][j-1]=='#')add(id(i,j),id(i,R[i][j]),1);
				else add(id(i,j),id(i,j-1),2);
				if(s[i][j+1]=='#')add(id(i,j),id(i,L[i][j]),1);
				else add(id(i,j),id(i,j+1),2);
				if(s[i+1][j]=='#')add(id(i,j),id(U[i][j],j),1);
				else add(id(i,j),id(i+1,j),2);
				if(s[i-1][j]=='#')add(id(i,j),id(D[i][j],j),1);
				else add(id(i,j),id(i-1,j),2);
			}
	priority_queue<array<int,3> >q;
	for(int i=1;i<=n*m;i++) dis[i]=to[i][0]=to[i][1]=to[i][2]=to[i][3]=inf;
	q.push({dis[t]=0,t,4});
	while(!q.empty())
	{
		auto tmp=q.top();q.pop();
		int x=tmp[0],now=tmp[1],c=tmp[2];
		if(vis[now][c])continue;vis[now][c]=1;
		int nx=(now-1)/m+1,ny=(now-1)%m+1;
		x=-x;
		if(c==4)
		{
			for(auto _:g[now])
			{
				int v=_.first,w=_.second;
				if(dis[now]+w<dis[v])
					dis[v]=dis[now]+w,q.push({-dis[v],v,4});
			}
			for(int k=0;k<=3;k++)
		        if(s[nx-dx[k]][ny-dy[k]]=='#'&&s[nx+dx[k]][ny+dy[k]]!='#')
				{
					int tx=nx+dx[k],ty=ny+dy[k],nw=id(tx,ty);
					if(x+1<to[nw][k]) to[nw][k]=x+1,q.push({-(x+1),nw,k});
				}
		}
		else
		{
			if(x<dis[now]) dis[now]=x,q.push({-dis[now],now,4});
			if(s[nx+dx[c]][ny+dy[c]]!='#')
			{
				int nw=id(nx+dx[c],ny+dy[c]);
				if(x<to[nw][c])to[nw][c]=x,q.push({-x,nw,c});
			}
		}
	}
	if(dis[ss]==inf) cout<<-1;
	else cout<<dis[ss];
	return 0;
}

posted @ 2026-09-24 21:50  Engle_Chen  阅读(10)  评论(0)    收藏  举报