2025 SMU WINTER 2th

前言

内含round6,round7,牛客训5的补题

题目

round 6

https://vjudge.net/contest/690457

A

图形构造的题目,题目要求平衡(任意2×2正方形都同时包含W和R,并且数目不一样)
2×2的正方形也就有两种情况
WWWR or RRRW
那么奇数行一列R一列W,偶数行全R
但还是要注意题目条件啊,,输出不要空格(在这里wa。。)

B

贪心
赛时模模糊糊把思路整出来了其实,但终还是模模糊糊(因为以为自己思路没把n秒时间考虑进去,但其实考虑了),后面写别的去了〒▽〒
:存结构体,把数据按结束时间排列。以最小的结束时间作为现在时间。后续通过不断遍历(如果当前遍历到的结束时间比我的“现在时间”晚,那么我就cnt++,并且更新现在时间

C

贪心+前缀和+二分
:题目想要求一定容量的书最多能容下多少故事。
但是会发现数据很大,所以就先把故事页数从小到大排序,前缀和处理,再二分去找每次查询的书最多能容下多少故事。

D

用的队列写的
上个学期培训,我记着好像有学长讲了个类似的题目来着。
:阅读题目可将题意归纳成所有的左括号是否都有其相应的右括号匹配。一个一个读取括号,如果是右括号并且队列的首元素是左括号那么就pop,否则存入队列中

E

n支队伍一个月后比赛,赢方+3分,平局都加1。现在教练进行培训,会使培训的队伍+1.问如何使,一个月之后比赛所有队伍的总分和最大。
赛时有点没看明白题目啊,,,(但现在看真不知道为什么没看明白)
:教练培训的结果要使所有的队伍的实力都不一样
存数组,从小到大排序。依次遍历,如果当前元素小于等于上一个元素,那么就进行处理。

注意的是:题目的数据还算比较大的,所以处理的时候while循环是不行的。(lyq最直接想这个方法哈〒▽〒)

点击查看代码
void solve() 
{
    ll n;cin>>n;
	ll a[n+10]={0};
	
	for(ll i=1;i<=n;++i)
	{
		cin>>a[i];
	}
	sort(a+1,a+1+n);
	ll ans=0;
	for(ll i=2;i<=n;++i)
	{
		if(a[i]<=a[i-1])
		{
			ans+=a[i-1]-a[i]+1;    //标记一下,这样就能把while循环去掉了
			a[i]=a[i-1]+1;
		}
	}
	cout<<ans<<'\n';
}

F

高精度加法
之前在洛谷上遇到了这种,终于在春假的时候学了遍哇咔咔(❁´◡`❁)

点击查看代码
vector<ll>add(vector<ll>&a,vector<ll>&b)
{
	if(a.size()<b.size())
	{
		return add(b,a);
	}
	vector<ll>c;
	ll t=0;
	for(ll i=0;i<a.size();++i)
	{
		t+=a[i];
		if(i<b.size())
		{
			t+=b[i];
		}
		c.push_back(t%10);
		t/=10;
	}
	if(t)
	{
		c.push_back(t);
	}
	return c;
}

vector<ll>a,b,c;
string s1,s2;

void solve()
{
    cin>>s1>>s2;
	for(ll i=s1.size()-1;i>=0;i--)
	{
		a.push_back(s1[i]-'0');
	}
	for(ll i=s2.size()-1;i>=0;--i)
	{
		b.push_back(s2[i]-'0');
	}
	c=add(a,b);
	for(ll i=c.size()-1;i>=0;i--)
	{
		cout<<c[i];
	}
	cout<<'\n';
}	

G

恼火的一个题哇〒▽〒
补题的时候发现我错误的原因是,直接把认为是同向的就判错,但其实不是
一个是异向的时候,如果两个相背而行,这肯定是不行的
二个是同向的时候,如果快的在后面,他是会追上慢的那个的

点击查看代码
void solve()
{
	ll a1,t1,p1;cin>>a1>>t1>>p1;
	ll a2,t2,p2;cin>>a2>>t2>>p2;
	double v1=(p1-a1)*1.0/t1;
	double v2=(p2-a2)*1.0/t2;
    
	double t=0;
	
	if(v1==v2)
	{
		cout<<"-1\n";
	}else{
		t=(a2-a1)*1.0/(v1-v2);
		if(t>=0)
		{
			cout<<fixed<<setprecision(8)<<t<<'\n';
		}else{
			cout<<"-1\n";
		}
	}
}

H

mark一下,其实我还是有点似懂非懂。留在这多看会。
但还是学到了d和dx去分割“AAAA...”“ABAB..”...等序列的范围(我自己在补题的时候有意识想去分割,但没想到合适的方法)

点击查看代码
void solve() {
    ll n,k;cin>>n>>k;
	if(n==1)
	{
		if(k==0)
		{
			cout<<"ABC\n";
		}else{
			cout<<"-1\n";
		}
		return;
	}
	if(k>(n-1)*2+n-2)
	{
		cout<<"-1\n";
		return;
	}
	if(k==1)
	{
		cout<<"ABA";
		for(ll i=2;i<n;++i)
		{
			cout<<"CBA";
		}
		cout<<"CCB"<<'\n';
		return;
	}
	
	ll d=0,dx=0;
	for(ll i=2;i<=n;++i)
	{
		ll temp=(i-1)*2+i-2;
		if(temp==k||temp==(k-1)||temp==(k-2))
		{
			if(temp==k)
			{
				d=0;
			}else if(temp==k-1)
			{
				d=1;
			}else{
				d=2;
			}
			dx=i;
			break;
		}
	}
	
	if(d==0)
	{
		for(ll i=1;i<=dx;++i)
		{
			cout<<"A";
		}
		for(ll i=1;i<=dx;++i)
		{
			cout<<"BC";
		}
		for(ll i=dx+1;i<=n;++i)
		{
			cout<<"ABC";
		}
		cout<<'\n';
	}
	else if(d==1)
	{
		for(ll i=1;i<=dx;++i)
		{
			cout<<"A";
		}
		cout<<"C";
		for(ll i=1;i<=dx;++i)
		{
			cout<<"BC";
		}
		for(ll i=dx+1;i<n;++i)
		{
			cout<<"ABC";
		}
		cout<<"AB";
		cout<<'\n';
	}else{
		for(ll i=1;i<=dx;++i)
		{
			cout<<"A";
		}
		cout<<"BC";
		for(ll i=1;i<=dx;++i)
		{
			cout<<"BC";
		}
		for(ll i=dx+1;i<n;++i)
		{
			cout<<"ABC";
		}
		cout<<"A"<<'\n';
	}
}

I

说实话最开始补题的时候没太看懂题(感觉阅读能力还是要提高(lyq喜欢跳着看))〒▽〒
题意大概为:过路的两个人分别手持1和n元,两个强盗要重新规划两人的钱。一个人分a1×p(p是a1的质因数),一个分a2/p。如果还有剩下的钱就归强盗;否则强盗要倒贴钱。
:要是强盗拿的钱最多,则要使过路人拿的钱最少。即max((n+1)-(1×p)-(n/p))
那么就是枚举质因数了。但只要第一个质因数就行了(n+1)-(1*p)-(n/p)这是个增函数。(还能这么判哇咔咔)

点击查看代码
void solve() {
    ll n;cin>>n;
	ll ans=0;
	for(ll i=sqrt(n);i>0;--i)
	{
		if(n%i==0)
		{
			ans=(1+n)-(i+n/i);
			cout<<ans<<'\n';
			return;
		}
	}
}

J

题意是在给出的字符串中查找cat(最多能有一个字符不一样)。
赛时感觉能做出来那时候,但写到后面发现前面疏忽了,思路就乱了。
:补题的时候发现,其实只要看是否存在ca或at或ct就行了

点击查看代码
void solve() {
    string s;cin>>s;
	ll len=s.size();
	
	ll x=-1,y=-1,z=-1;
	
	//ca
    x=s.find('c',0);
	if(x>-1&&x<(len-1))
	{
		y=s.find('a',x+1);
	}
	if(x!=-1&&y!=-1&&y<len-1)   //不是<=是因为string是从0到n的左闭右开区间
	{
		cout<<x+1<<" "<<y+1<<" "<<y+2<<'\n';
	    return;
	}
	
	//ct
	x=y=z=-1;
	x=s.find('c',0);
	if(x>-1&&x<(len-2))
	{
		z=s.find('t',x+2);
	}
	if(x!=-1&&z!=-1)
	{
		cout<<x+1<<" "<<x+2<<" "<<z+1<<'\n';
		return;
	}
	
	//at
	x=y=z=-1;
	y=s.find('a',1);
	if(y>-1&&y<len-1)
	{
		z=s.find('t',y+1);
	}
	if(y!=-1&&z!=-1)
	{
		cout<<1<<" "<<y+1<<" "<<z+1<<'\n';
	    return;
	}
	cout<<"-1\n";
	return;
}

round 6总结

做出四题
这天有些小事,但也没很影响比赛。感觉过年还是有些舒坦了,还是有点没回过神。赛后也没有立马补题。还是得快快调整。
而且这次wa的两回都是很粗枝大叶的错误,一个是输出格式错,一个是没开long long〒▽〒

round 7

https://vjudge.net/contest/690739
4/7
这回没罚时欸,前两题的速度也还可以,但是到第三题就慢下来了〒▽〒

A

题意:检查每个给出的字符串是否是yes(任意大小写模式)
:依次判断给出的是否是Y或y,E或e,S或s即可

B

最开始没太懂题目,后面看后面的样例看明白的
题意:同样的也是,给一串字符串,每个字符第一次出现的时候+2,其他的时候+1,问和是多少
:开个map,键值对。初始化答案就为mp.size(),然后遍历mp,依次加上值。(个人感觉set也行)

C

这个题目耗时挺久的,相较于其他完成这道题目的同学来说。原因总结来是,最初的思路不算特别清晰,导致后面从结果往前推的时候有点卡。
题意:一个密码锁扣,现已知进行的操作和操作后的数字,要求推出操作前的。
:对于每个数字反推,如果是U,那么就--,如果操作前是0,那么就为9;

点击查看代码
void solve() 
{
    ll n;cin>>n;
	ll a[n+10]={0};
	for(ll i=1;i<=n;++i)
	{
		cin>>a[i];
	}
	ll j=1;
	
    while(j<=n)
	{
		ll x;cin>>x;
		string s;cin>>s;
	//	ll temp=0;
		for(ll k=0;k<(ll)s.size();++k)
		{
		
			if(s[k]=='U')
			{
				if(a[j]==0)
				{
					a[j]=9;

				}else
    				a[j]--;
			}else{
				if(a[j]==9)
				{
					a[j]=0;
				}else
	    		{
					a[j]++;
				}
		    }
		}
	    j++;
	}
	for(ll i=1;i<=n;++i)
	{
		cout<<a[i]<<" ";
	}
	cout<<'\n';
}

D

最开始也是真的没看懂题目,也是看样例读懂的--原来给出的字符串是一组的。
题意:给出一组字符串,分别判断每一个字符串是否能由同组的其他两个字符串组合而成。
:要用到substr函数。首先都存入数组,开map,对于每个数组里的字符串元素,都for循环去遍历分割(substr函数),如果分割出来的两个函数在map里存在就ok

点击查看代码

void solve() 
{
    ll n;cin>>n;
	vector<string>a(n);
	map<string,bool>mp;
	vector<bool>vis(n,false);
	for(ll i=0;i<n;++i)
	{
		string s;cin>>s;
		a[i]=s;
		mp[s]=true;
	//	vis[i]=0;
	}
	for(ll i=0;i<n;++i)
	{
		ll len=a[i].size();
		bool flag=0;
		for(ll j=1;j<len;++j)
		{
			string s1=a[i].substr(0,j);
			string s2=a[i].substr(j);
			if(mp[s1]&&mp[s2]){
				flag=true;
				break;
			}
		}
		if(flag){
			vis[i]=true;
		}
	}
	for(ll i=0;i<n;++i)
	{
		if(vis[i])
		{
			cout<<"1";
		}else{
			cout<<"0";
		}
	}
	cout<<'\n';
	
	
}

E

题意:要使给出的矩形旋转90,180,270,360都要是一样的图案,最少操作多少次
:抽象一点思考。要使每次矩阵都相同,即a[i][j]=a[j][n-i+1]=a[n-i+1][n-j+1]=a[n-j+1][i]
遍历数组(注意,输入数据是连在一块的,要开char数组),看每一个改成1或0最少要多少,把每一次得到的值相加即可。

点击查看代码
char a[N][N];
bool vis[N][N];
void solve()
{
	ll n;cin>>n;
    memset(a,0,sizeof a);
	memset(vis,false,sizeof vis);
	
	for(ll i=1;i<=n;++i)
	{
		for(ll j=1;j<=n;++j)
		{
			cin>>a[i][j];
		}
	}
	ll ans=0;
	for(ll i=1;i<=n;++i)
	{
		for(ll j=1;j<=n;++j)
		{
			if(i==j&&n%2==1)
			{
				continue;
			}
			if(!vis[i][j])
			{
				ll cnt=0;
				if(a[i][j]=='1')
				{
					cnt++;
				}
				vis[i][j]=true;
				if(a[j][n-i+1]=='1')
				{
					cnt++;
				}
				vis[j][n-i+1]=true;
				if(a[n-i+1][n-j+1]=='1')
				{
					cnt++;
				}
				vis[n-i+1][n-j+1]=true;
				if(a[n-j+1][i]=='1')
				{
					cnt++;
				}
				vis[n-j+1][i]=true;
				ans+=min(cnt,4-cnt);
				
			}
		}
	}
	cout<<ans<<'\n';
	return;
}

F

题意:在给出的数组中找满足ai<i<aj<j的个数
:ai<i和aj<j其实是一样的,所以在aj前满足ai即可

点击查看代码
const ll N = 2e6 + 10;
ll a[N];
ll b[N];

void solve() {
    ll n;cin>>n;
	ll ans=0;

	for(ll i=1;i<=n;++i)
	{
		cin>>a[i];
		b[i]=b[i-1]+(a[i]<i);
		if(a[i]<i&&(a[i]-1)>=1)
		{
			ans+=b[a[i]-1];
		}
	}
	cout<<ans<<'\n';
}

牛客训5

连续打了好几次牛客了,感觉状态一次比一次好(●'◡'●)。
这一回我做的是A,J,L题。L死磕了很久没做出来〒▽〒

A

反思:
因为之前vj上训练的那个高精度的题目就是做之前我发现数据很大,这次看到1e18的数据想了要不要开高精度来着(但是后面想long long的数据最大就是1e18)。但这也浪费了时间〒▽〒。该清楚记得的东西就要记住啊,,

J

题目下面给了个图感觉还是很仁慈的。虽然这道题难度不大。但lyq没那个图的话上来就会画高中学的v-t图像。。。
:看图,就像v-t图像一样,距离是面积。然后留神下速度减小时的判断就ok。

L

image

看题目的时候注意到是数据是1e6,暴力的去枚举的话肯定会t的。但我还是写了遍三次循环的,想着后续用什么来优化一下。后面发现不行,回归到了最开始的思路,三个一组,按偶奇偶排列,但是也不行,偶奇偶之后就是奇偶奇。。。
看题解说是:六个一组,image
(x+2,x+5都是3的倍数,豪强哇〒▽〒)

下面这个是我补题的时候不断wa不断修改的代码,有点丑。

点击查看代码
void solve() {
    ll n;cin>>n;
	ll ans=n/3;
	vector<ll>a;
//	cout<<ans<<'\n';
	if(n<=3)
	{
		cout<<0<<'\n';
		return;
	}else{
		cout<<ans<<'\n';
	}
	if((n%6)<=2)
	{
		for(ll i=1;i<=n;i+=6)
		{
			a.push_back(i);
			if(i+1<=n)	a.push_back(i+1);
			//	else break;
			if(i+3<=n)  a.push_back(i+3);
			//	else break;
			if(i+2<=n)  a.push_back(i+2);
			//	else break;
			if(i+4<=n)  a.push_back(i+4);
			//	else break;
			if(i+5<=n)  a.push_back(i+5);
			//	else break;
		}
		ll cnt=1;
		for(ll i=0;i<(ll)a.size();i+=3)
		{
			if(cnt<=ans)
			{
				cout<<a[i]<<" "<<a[i+1]<<" "<<a[i+2]<<'\n';
				cnt++;
			}else{
				break;
			}
		}
	}else{
		if(n>=4&&n<6)
		{
			cout<<"1 2 4\n";
		}else if(n>=6&&n<9)
		{
			cout<<"1 2 4\n3 5 9\n";
		}else
		cout<<"1 2 4\n3 5 9\n7 8 6\n";
		ll cnt=3;
		for(ll i=10;i<=n;i+=6)
		{
			a.push_back(i);
			if(i+1<=n)	a.push_back(i+1);
			//	else break;
			if(i+4<=n)  a.push_back(i+4);
			//	else break;
			if(i+2<=n)  a.push_back(i+2);
			//	else break;
			if(i+3<=n)  a.push_back(i+3);
			//	else break;
			if(i+5<=n)  a.push_back(i+5);
			//	else break;
		}
		for(ll i=0;i<(ll)a.size();i+=3)
		{
			if(cnt<ans)
			{
				cout<<a[i]<<" "<<a[i+1]<<" "<<a[i+2]<<'\n';
				cnt++;
			}else{
				break;
			}
		}
		
	}
}
好看版
void solve() {
	int n;
	cin>>n;
	if (n<=3) {
		cout<<0<<endl;
	}
	else if (n<=5) {
		cout<<"1"<<endl;
		cout<<"2 3 4"<<endl;
	}
	else {
		cout<<n/3<<endl;
		int c=1;
		if (n%6<3) {
			for (;c<=n/3*3;) {
				cout<<c<<" "<<c+1<<" "<<c+3<<endl;
				cout<<c+2<<" "<<c+4<<" "<<c+5<<endl;
				c+=6;
			}
		}
		else {
			cout<<"1 2 4\n3 5 9\n7 8 6\n";
			c=10;
			for (;c<=n/3*3;) {
				cout<<c<<" "<<c+1<<" "<<c+4<<endl;
				cout<<c+2<<" "<<c+3<<" "<<c+5<<endl;
				c+=6;
			}
		}
	}
}

总结

这周打的vj上r6,r7,牛客4,5。vj上的题基本上补完了,但是牛客的还有很多没有补的〒▽〒
还是得多抓紧点时间。
还有就是我觉得还是得学点东西,在练习之余。之前培训教的东西好几个都其实没通透。之后得找时间把那个给捋一捋。

posted @ 2025-02-04 23:40  YuanqLi  阅读(19)  评论(0)    收藏  举报