2026 WINTER 1st

这周补题觉得有收获的是
r1的c d
r2的c
r3的e
r4的d
这周事情比较多,训练补题没能及时更上,下周事情少了,把这周少做的补上

一些感想:
赛时感觉脑子转的比之前慢,果然还是期末周空了一会训练啊
但现在比之前更喜欢看公式推理了(?

补题

r1

A. Shovels and Swords

这题赛时比较速度的过了,但思路下来自己回顾的时候发现并不严谨(赛时就是突然想到了(a+b)/3),重新捋了捋
设mn=min(a,b),mx=(a,b);
容易观察得到,2×mn<=mx,答案就直接是mn
2×mn>mx时,每次都消耗当前数量比较多的,最后材料总是不足3,即可视作任意三个材料都能换一个宝石

B. Shuffle

记录可达区间,不断扩展即可

点击查看代码
void solve()
{
	ll n,x,m;cin>>n>>x>>m;
	bool ok=false;
	ll lx=x,ly=x;
//	ll ans=0;
	while(m--){
		ll l,r;cin>>l>>r;
		if(l==1&&r==n&&!ok){
			cout<<n;
			ok=true;
		}else{
			if(l<=ly&&r>=lx){
				lx=min(lx,l);
				ly=max(ly,r);
				
			}
		}
	}
	if(!ok){
		cout<<ly-lx+1;
	}
	
}

C. Palindromic Paths

要让芯片从(1,1)走到指定位置的任意路径都是回文的,即所有路径的第k个位置和第(n+m-k)个位置的数字完全相同。
对于矩阵中的任意位置(i,j),步数标记为s=i+j-1,那么s的对称组为s'=n+m-s
然后遍历矩阵,先统计每个步数统计为s的0/1数量
再遍历所有要配对的对称组,从1到n+m-1,并只遍历前半部分,避免重复
得到答案

点击查看代码
void solve()
{
	ll n,m;cin>>n>>m;
	ll ans=0;
	ll cnt0[100]={0},cnt1[100]={0};
	for(ll i=1;i<=n;++i)
	{
		for(ll j=1;j<=m;++j){
			ll x;cin>>x;
			if(x==1){
				cnt1[i+j-1]++;
			}else{
				cnt0[i+j-1]++;
			}
		}
	}
	for(ll i=1;i*2<n+m;++i){
		ans+=min(cnt0[i]+cnt0[n+m-i],cnt1[i]+cnt1[n+m-i]);
	}
	cout<<ans;
	
}

D. Two Divisors

补题思路来自于:
https://www.cnblogs.com/lniiwuw/p/15515813.html

image
(直接贴图吧,这些公式好难打、、)

在补题代码旁边写了写注释,方便之后还能看懂在写啥

还是得谨慎用ll,补题第一发wa了个MLE,改成int就过了,下面代码是define ll int版本

点击查看代码
#include<bits/stdc++.h>
using namespace std;

#define ll int
#define endl '\n'

#define modd 998244353
const ll N=1e7+10;
bool vis[N];//标记是否为素数
ll p[N];//存储所有素数
ll ap[N];//ap存储x的最小质因数
ll tot;//素数计数
ll ans[N][2];

//预处理1e7以内所有素数、记录每个合数的最小质因数并存在ap数组
void getprime(){
	memset(vis,1,sizeof vis);
	vis[0]=vis[1]=0;
	for(ll i=2;i<N;++i){
		if(vis[i]) p[++tot]=i;
		for(ll j=1;j<=tot&&1ll*i*p[j]<N;++j){
			vis[i*p[j]]=0;
			ap[i*p[j]]=p[j];
			if(i%p[j]==0) break;
		}
	}
}

void solve()
{
	getprime();
	ll n;cin>>n;
	ll a;
	for(ll i=1;i<=n;++i){
		cin>>a;
		if(vis[a]) ans[i][0]=ans[i][1]=-1;//素数
		else{
			ll tmp=ap[a],b=1;
			while(a%tmp==0) a/=tmp,b*=tmp;
			if(a!=1) ans[i][0]=b,ans[i][1]=a;
			else ans[i][0]=ans[i][1]=-1;
		}
		
	}
	for(ll i=1;i<=n;++i){
		cout<<ans[i][0]<<" ";
	}
	cout<<'\n';
	for(ll i=1;i<=n;++i){
		cout<<ans[i][1]<<" ";
	}
}

int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	ll lll=1;
//	cin>>lll;
	while(lll--)
	{
		solve();
		if(lll) cout<<'\n';
	}
	return 0;
}

r2

A. Berland Poker

分类讨论王牌数量是否大于一个人能拿的最大数
如果小于,直接输出王牌数量
否则胜者拿满王牌(他能拿到的最大数量牌数),其他的分给k-1玩家,计算最大王牌数,再计算得分

B. New Theatre Square

先通过 y 与 2x 的大小判断 1×2 瓷砖的性价比:若 y ≥ 2x,1×2 瓷砖无优势,直接用 1×1 瓷砖覆盖所有白色方块;若 y < 2x,则按行遍历统计被黑色方块分隔的连续白色段,每个段优先用 1×2 瓷砖(段长/2)覆盖,剩余单块白色方块用 1×1 瓷砖,最终累加两类瓷砖的花费得到最小成本。

点击查看代码
void solve()
{
	ll n,m,x,y;cin>>n>>m>>x>>y;
	ll cntx=0,cnty=0;
	if(2*x<=y){
		for(ll i=1;i<=n;++i){
			for(ll j=1;j<=m;++j){
				char c ;cin>>c;
				if(c=='.') cntx++;
			}
		}
		cout<<cntx*x;
	}else{
		ll tmp=0;
		for(ll i=1;i<=n;++i){
			for(ll j=1;j<=m;++j){
				char c;cin>>c;
				if(c=='.'){
					tmp++;
				}else{
					cnty+=(tmp/2),cntx+=(tmp%2);
					tmp=0;
				}
			
			}
			cnty+=(tmp/2);
			cntx+=(tmp%2);
			tmp=0;
		}
		cout<<(cntx*x+cnty*y);
	}
}

C. Mixing Water

r3

A. Sum of Odd Integers

通过两个关键条件判断:
1.n 与 k 需奇偶性一致(因 k 个互不相同正奇数的和的奇偶性与 k 相同)
2.其次,n 需不小于 k²(因 k 个互不相同正奇数的最小和为 1+3+…+(2k-1)=k²),仅当两个条件同时满足时,n 可表示为 k 个互不相同的正奇数之和,否则不可。

B. Princesses and Princes

贪心模拟做法
用数组标记已匹配的王国,遍历每个女儿的心仪列表,优先匹配列表中未被占用的最小编号王国,记录未匹配到任何王国的女儿;若所有女儿均匹配成功则输出 “OPTIMAL”,否则找到未被匹配的王国,将其添加到该未匹配女儿的列表中,输出 “IMPROVE” 及对应的女儿和王国编号。

点击查看代码
void solve()
{
	ll n;
	cin>>n;
	ll k[n+5];
	ll b[n+5]={0};
	ll ans=0;
	for(ll i=1;i<=n;i++)
	{
		cin>>k[i];
		bool ok=0;
		for(ll j=1;j<=k[i];j++)
		{
			ll x;
			cin>>x;
			if(b[x]==0&&ok==0)
			{
				b[x]++;
				ok=1;
			}
		}
		if(ok==0)
			ans=i;
	}
	if(!ans)
	{
		cout<<"OPTIMAL";
		return;
	}
	cout<<"IMPROVE\n";
	for(ll i=1;i<=n;i++)
	{
		if(b[i]==0)
		{
			cout<<ans<<" "<<i;
			return;
		}
	}
}

C. Game with Chips

由于每次操作会同时作用于所有芯片,无法单独控制某一个,因此采用统一路径。先用 U、L 把所有芯片推到左上角边界,保证起点一致;随后按“蛇形遍历”方式完整扫描整个棋盘,使每一个格子都会被经过一次。这样,只要目标位置在棋盘内,当路径经过该格子时,对应芯片必然访问到目标。
整个路径长度不超过2nm,满足操作次数限制。

蛇形遍历还想了下咋写 晕

点击查看代码
void solve()
{
	ll n,m,k;
	cin>>n>>m>>k;
	
	for(ll i=1;i<=k;i++)
	{
		ll x,y;
		cin>>x>>y;
	}
 
	for(ll i=1;i<=k;i++)
	{
		ll x,y;
		cin>>x>>y;
	}
	
	string ans;
	
	for(ll i=1;i<=n-1;i++) ans.push_back('U');
	for(ll i=1;i<=m-1;i++) ans.push_back('L');
 
	
	for(ll i=1;i<=n;i++)
	{
		if(i&1)
		{
			for(ll j=1;j<=m-1;j++) ans.push_back('R');
		}
		else
		{
			for(ll j=1;j<=m-1;j++) ans.push_back('L');
		}
		if (i!=n) ans.push_back('D');
	}
	
	cout<<ans.size()<<endl;
	cout<<ans;
}

r4

A. New Year Garland

最多的颜色必须被其他颜色隔开,即满足mx<=(sum-mx)+1
满足Yes,否则No

B. Verse For Santa

按顺序累加朗诵时间 sum,同时维护当前前缀中耗时最大的部分 maxa 及其位置。

对于每个i,有两种可能:
1.不跳过任何部分:若 sum ≤ s,可以完整朗诵前 i 段。
2.跳过一个部分:若 sum - maxa ≤ s,则跳过当前前缀中耗时最大的那一段,可以朗诵 i-1 段。

在遍历过程中,始终记录能朗诵的最大段数,并保存对应应跳过的那一段位置。
最后输出结果

C. Stack of Presents

复用已经翻开的部分

按送礼顺序处理,用 pos[x] 表示礼物在初始栈中的位置,mx 表示目前已翻到的最深位置。
若 pos[b[i]] ≤ mx,礼物已在翻开的部分中,直接取走,耗时 1。
否则需翻到该位置,耗时 2·(pos[b[i]]−i)+1,并更新 mx。
累加所有耗时即为最小时间。

点击查看代码

void solve()
{
	ll n,m;cin>>n>>m;
	
	ll a[n+10]={0},b[m+10]={0};
	vector<ll>pos(n+1);
	for(ll i=1;i<=n;++i){
		cin>>a[i];
		pos[a[i]]=i;
	}
	for(ll i=1;i<=m;++i){
		cin>>b[i];
	}
	
	ll ans=0;
	ll mx=0;
	
	for(ll i=1;i<=m;++i){
		if(pos[b[i]]<=mx){
			ans++;
		}else{
			ans+=2ll*(pos[b[i]]-i)+1;
			mx=pos[b[i]];
		}
	}
	cout<<ans;
	
}
posted @ 2026-01-24 20:28  YuanqLi  阅读(2)  评论(0)    收藏  举报