ABC375 Review

ABC375 Review

A B

模拟题 过

C

很让人恼怒的一道题,思路一点也不难想,但是代码实现过于困难了(对于我来说)

分析

自己找一两组样例就会发现这道题实际上实在模拟一个矩阵不断向内旋转 \(90°\) 的过程,从外到里旋转的次数越来越多,旋转的过程可以发现实际上可以通过模 \(4\) 来进行简化,然后只需做一个坐标的映射就可以了,难度完全在于代码实现上面。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=3010;
char mp[N][N],ans[N][N];
int n;
inline void pre()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		getchar();
		for(int j=1;j<=n;++j)mp[i][j]=getchar(),ans[i][j]=mp[i][j];
	}
}
inline void debug()
{	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)putchar(ans[i][j]);
		putchar('\n');
	}
	
}
inline void getans(int x)
{
	
	int y=n-x+1;
	int times=x%4;
		if(times==0)
			{
				for(int j=x;j<=y;++j)ans[x][j]=mp[x][j],ans[y][j]=mp[y][j];
				for(int i=x+1;i<=y-1;++i)ans[i][x]=mp[i][x],ans[i][y]=mp[i][y];
			}
		else if(times==1)
			{
				for(int j=x;j<=y;++j)ans[x][j]=mp[n-j+1][x],ans[y][j]=mp[n-j+1][y];
				for(int i=x+1;i<=y-1;++i)ans[i][x]=mp[y][i],ans[i][y]=mp[x][i];
			}
		else if(times==2)
			{
				for(int j=x;j<=y;++j)ans[x][j]=mp[y][n-j+1],ans[y][j]=mp[x][n-j+1];
				for(int i=x+1;i<=y-1;++i)ans[i][x]=mp[n-i+1][y],ans[i][y]=mp[n-i+1][x];
			}
		else if(times==3)
			{
				for(int j=x;j<=y;++j)ans[x][j]=mp[j][y],ans[y][j]=mp[j][x];
				for(int i=x+1;i<=y-1;++i)ans[i][x]=mp[x][n-i+1],ans[i][y]=mp[y][n-i+1];
			}
//	putchar('\n');
//	debug();
}
inline void solve()
{
	for(int i=1;i<=n/2;++i)getans(i);
	debug();
}
int main()
{
	pre();
	solve();
	return 0;
 } 

D

\(S\) 里找到长度为 \(3\) 的回文串的数量

分析

由于长度只有 \(3\) ,所以可以直接枚举中间的那个字母,然后找两边一样的即可,产生的答案是两边相同字母数量分别乘积然后再求和。

小坑点

这个会爆 int ,一开始想到了,但是写的时候还是 wa 了一发,实际上直接 define 或许会更加方便一点。

Code

#include<bits/stdc++.h>
using namespace std;
string s;
long long ans;
const int N=2e5+10;
int l[N][30],r[N][30];
inline void pre()
{
	cin>>s;
	for(int i=1;i<s.length();++i)
	{
		for(int j=0;j<26;++j)
		{
			l[i][j]=l[i-1][j];
			if(s[i-1]==j+'A')l[i][j]++;	
		}	
	}
	for(int i=s.length()-2;i>=0;--i)
	{
		for(int j=0;j<26;++j)
		{
			r[i][j]=r[i+1][j];
			if(s[i+1]==j+'A')r[i][j]++;	
		}		
	}		
}
inline void solve()
{
	for(int pos=1;pos<s.length()-1;++pos)
		for(int i=0;i<26;++i)
			ans+=1ll*l[pos][i]*r[pos][i];
	cout<<ans;
}
int main()
{
	pre();
	solve();
	return 0;
 } 

E

每个人初始属于三个集合中的某一个,且带有一个初始价值,求一个最小的移动数量,使得三个集合的总价值相同,(如果有的话)。

分析

现在算是总结出来一个规律,只要是没什么清晰思路的题目,十有八九是个dp。

这个数据范围那肯定爆搜是会G的,看这种集合划分问题,一般可能就是dp了。

仔细想想,后面的人怎么选,也不会影响前面的选择,只是需要一个阶段和三个状态,以为一定会 T,所以没有去写(实际上说时间也是不够了)。

implementation

当任何一个阶段 \(i\) 完成之后,如果 前两个集合的价值是确定的,那么一定有一个唯一的 第三个集合的价值 与之对应, 那么你只需要从 \(1-n\) 枚举每一个人,然后讨论把他丢到哪一个集合即可,

收获

发现日本人十分喜欢使用vector

vector 可以快速赋值,定长度vector和数组基本上没有什么区别

vector 可以快速复制,函数是 newvec=move(vec);

Code

#include<bits/stdc++.h>
using namespace std;
const int N=1000,inf=1e9+7;
int n,s,tar,a[N],b[N];
inline void pre()
{
	cin>>n;
	for(register int i=1;i<=n;++i)
	{
		cin>>a[i]>>b[i];
		s+=b[i];
	}
}
inline void solve()
{
	if(s%3)
	{cout<<"-1";return ;}
	tar=s/3;
	vector<vector<int>> dp(tar+10,vector<int>(tar+10,inf));
	dp[0][0]=0;
	for(int i=1;i<=n;++i)
	{
		int w=b[i];
		vector<vector<int>> dp1(tar+10,vector<int>(tar+10,inf));
		for(int j=0;j<=tar;++j)
		{
			for(int k=0;k<=tar;++k)
			{
				if(a[i]==1)
				{
					if(j-w>=0)dp1[j][k]=min(dp1[j][k],dp[j-w][k]);
					if(k-w>=0)dp1[j][k]=min(dp1[j][k],dp[j][k-w]+1);
					dp1[j][k]=min(dp1[j][k],dp[j][k]+1);					
				}
				else if(a[i]==2)
				{
					if(j-w>=0)dp1[j][k]=min(dp1[j][k],dp[j-w][k]+1);
					if(k-w>=0)dp1[j][k]=min(dp1[j][k],dp[j][k-w]);
					dp1[j][k]=min(dp1[j][k],dp[j][k]+1);
				}
				else
				{
					if(j-w>=0)dp1[j][k]=min(dp1[j][k],dp[j-w][k]+1);
					if(k-w>=0)dp1[j][k]=min(dp1[j][k],dp[j][k-w]+1);
					dp1[j][k]=min(dp1[j][k],dp[j][k]);	
				}
			}
		}
		dp=move(dp1);
	}
	cout<<(dp[tar][tar]==inf?-1:dp[tar][tar]);
}
int main()
{
	pre();
	solve();
	return 0;
}

F

看起来像是一个最短路,于是写了一个超级暴力。。。。

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
const int N=500,M=3e5+1;
const int INF=2005120700;
struct Edge
{
	int v,nex,w;
}E[M];
int tote,head[N];
inline void add(int u,int v,int w)
{
	E[++tote].v=v,E[tote].w=w,E[tote].nex=head[u];
	head[u]=tote;
}
bool blocked[M];
int n,m,q,u,v,w;
inline void dijkstra(int s,int t)
{
	vector<int> vis(n+1,0);
	vector<int> dis(n+1,INF);
	priority_queue< pair<int,int> > q;
	q.push(make_pair(0,s)),dis[s]=0;
	while(q.size())
	{
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;
		for(int i=head[x];i;i=E[i].nex)
		{
			if(blocked[i])continue;
			int v=E[i].v;
			if(dis[x]+E[i].w>dis[v])continue;
			dis[v]=E[i].w+dis[x];
			q.push(make_pair(-dis[v],v));
		}
		vis[x]=1;
	}
	int res=dis[t];
	wr(res==INF?-1:res),putchar('\n');
}
inline void solve()
{
	re(n),re(m),re(q);
	for(register int i=1;i<=m;++i)
	{
		re(u),re(v),re(w);
		add(u,v,w);
		add(v,u,w);
	}
	int opt;
	while(q--)
	{
		re(opt);
		if(opt==1)
		{
			re(u);
			blocked[2*u]=blocked[2*u-1]=1;	
		}
		else
		{
			re(u),re(v);
			dijkstra(u,v);
		}
	}
}
int main()
{
	solve();
	return 0;
} 
posted @ 2024-10-14 09:47  Hanggoash  阅读(11)  评论(0编辑  收藏  举报
动态线条
动态线条end