牛客周赛 Round 68(A~E)

比赛链接:https://ac.nowcoder.com/acm/contest/95928#question
这次D题小细节搞了好久,越界了好几次,没想到赛后做E,发现还更简单

A.三途川的摆渡人(二)

题面:

小红这天来到了三途川,发现这里有一个摆渡人,名字叫小町。
小町的职责是将一些灵魂运送到冥界。但小町非常喜欢偷懒,她经常在上班的时候摸鱼,导致很多灵魂不能成功送达,因此在彼岸开出了许多彼岸花。

小红准备统计彼岸花的数量,她把排队等待摆渡的灵魂用一个01串来表示,'0'代表因小町摸鱼未能上船的灵魂,'1'代表成功到达冥界的灵魂。每个未上船的灵魂都将化为一朵彼岸花,请你帮小红计算彼岸花的数量。
输入:

第一行输入一个正整数n,代表灵魂的数量。
第二行输入一个长度为n的01串,代表每个灵魂是否成功被小町送往冥界。
\(1<=n<=100\)
输出:
一个整数,代表彼岸花的数量。
样例:
4
0100
——————
3
思路:彼岸花数量就是字符串中0数量,直接遍历

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
int main()
{
	fio();
	ll n;
	cin>>n;
	string f;
	cin>>f;
	ll ans=0;
	for(ll i=0;i<f.size();i++)
	{
		if(f[i]=='0')ans++;
	}
	cout<<ans<<endl;
}

B.魔法之森的蘑菇(二)

题面:
小红在魔法之森迷路了,森林中有一些致幻的毒蘑菇。森林用一个𝑛行𝑚列的矩阵表示。
小红准备采集一个矩形区域里的资源,但小红非常讨厌蘑菇,因此她希望这个矩形内没有任何蘑菇。
小红希望你帮她计算出一个面积最大的、且不包含蘑菇的矩形区域。
输入:
第一行输入两个正整数𝑛,𝑚代表矩阵的行数和列数。
接下来的𝑛行,每行输入一个长度为𝑚的字符串,用来表示森林地图。
保证所有的字符仅有'.'和''这两种,其中'.'代表道路,''代表蘑菇
\(1<=n,m<=30\)
输出:
四个整数$ x_1$, \(y_1\), \(x_2\), \(y_2\),用空格隔开。代表矩形的左上角在第$ x_1 $行第 $ y_1 $ 列,右下角在第 \(x_2\) 行第 \(y_2\) 列。保证至少有一个合法的答案。
样例:
3 3
\(.*.\)
\(...\)
\(.*.\)
——————
1 1 3 1
思路:二维前缀和+暴力枚举,首先用二维前缀处理好所*的个数,然后暴力&n^4&枚举左上角和右下角,随后每次减一下检测一下是否全为0即可,然后再比较下当前面积和记录的最大面积。如果能更新就更新,然后更新2个点的坐标

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll pre[50][50];
int main()
{
	fio();
	ll n,m;
	cin>>n>>m;
	string f[50];
	for(ll i=1;i<=n;i++)cin>>f[i],f[i]='0'+f[i];
	for(ll i=1;i<=n;i++)
	{
		for(ll j=1;j<=m;j++)
		{
			pre[i][j]=pre[i][j-1]+pre[i-1][j]-pre[i-1][j-1]+(f[i][j]=='*');
		}
	}
	ll ans=0;
	ll l,r,l1,r1;
	for(ll i=1;i<=n;i++)
	{
		for(ll j=1;j<=m;j++)
		{
			for(ll k=i;k<=n;k++)
			{
				for(ll c=j;c<=m;c++)
				{
					// if(k==3&&c==3&&i==3&&j==1)
					// 	{
					// 		cout<<pre[k][c]-pre[k][j-1]-pre[i-1][c]+pre[i-1][j-1]<<endl;
					// 	}
					if(pre[k][c]-pre[k][j-1]-pre[i-1][c]+pre[i-1][j-1]==0)
					{
						
						if(ans<(c-j+1)*(k-i+1))
						{
							ans=(c-j+1)*(k-i+1);
							l=i,r=j,
							l1=k,r1=c;
						}
					}
				}
			}
		}
	}
	cout<<l<<" "<<r<<" "<<l1<<" "<<r1<<endl;
}

C.迷途之家的大贤者(二)

题面:

小红在穿越后不久,就被大贤者小紫发现了,于是小紫友好地请小红来迷途之家做客。

她们准备玩一个游戏,两人分别拿到了一个长度为 $n $ 的数组。她们可以进行若干次操作。

对于每次操作,两人可以同时删除自己数组中任意一个元素。她们希望两人通过若干次删除操作,使得操作后的两个数组中所有元素均互不相同。例如 \([1,2][3,4]\) 满足条件,而 \([1,2][2,3]\) 不满足条件,因为两个数组中有两个值为2的元素。

你能帮小红求出操作的最小次数吗?
输入:

第一行输入一个正整数 $n $,代表每个人数组的大小。

第二行输入 $ n $ 个正整数 $ a_i $,代表小红拿到的数组元素。

第三行输入 $ n $ 个正整数 $ b_i $,代表小紫拿到的数组元素。

$ 1 \leq n \leq 10^5 $

$ 1 \leq a_i, b_i \leq 10^9 $
输出:
一个整数,代表操作的最小次数。
样例:
4
1 2 1 3
2 4 3 5
————
2
思路:首先思考下,发现删除自己重复的数是最优先的,然后再删除和别人重复的是其次的,所以通过这种方法可以讨论,先分别记录两个数组的删自己重复数的次数:cnt,cnt1
如果cnt==cnt1
则剩下的数一定是重复的且其值为1,所以答案为(重复的数的种类+1)/2+cnt
如果cnt>cnt1
首先则剩下的两者重复的数,后者可以先删除cnt-cnt1个,随后答案为(重复的数的种类-(cnt-cnt1)+1)/2+cnt
否则反之

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll a[500000];
ll b[500000];
int main()
{
	fio();
	ll n;
	cin>>n;
	map<ll,ll>q1,q2;
	set<ll>f;
	for(ll i=1;i<=n;i++)
	{
		cin>>a[i];
		q1[a[i]]++;
		f.insert(a[i]);
	}
	for(ll i=1;i<=n;i++)cin>>b[i],q2[b[i]]++,f.insert(b[i]);
	ll ans=0;
	ll cnt=0;
	ll cnt1=0;
	for(auto j:f)
	{
		if(q1[j]>0)
		cnt+=q1[j]-1;
		if(q2[j]>0)
		cnt1+=q2[j]-1;
	}
	//ll ans=0;
	if(cnt==cnt1)
	{
		ll cs=0;
		for(auto j:f)
		{
			if(q1[j])q1[j]=1;
			if(q2[j])q2[j]=1;
			if(q1[j]&&q2[j])cs++;
		}
		cout<<(cs+1)/2+cnt<<endl;
	}
	else if(cnt>cnt1)
	{
		ll co=cnt-cnt1;
		ll cs=0;
		for(auto j:f)
		{
			if(q1[j])q1[j]=1;
			if(q2[j])q2[j]=1;
			if(q1[j]&&q2[j])
			{
				if(co)
				{
					co--;
					continue;
				}
				else 
				{
					cs++;
				}
			}
		}	
		cout<<(cs+1)/2+cnt<<endl;
	}
	else 
	{
		swap(cnt,cnt1);
		ll co=cnt-cnt1;
		ll cs=0;
		for(auto j:f)
		{
			if(q1[j])q1[j]=1;
			if(q2[j])q2[j]=1;
			if(q1[j]&&q2[j])
			{
				if(co)
				{
					co--;
					continue;
				}
				else 
				{
					cs++;
				}
			}
		}	
		cout<<(cs+1)/2+cnt<<endl;
	}
}

D.红魔馆的馆主(二)

题面:

小红来到了红魔馆。众所周知,红魔馆的馆主是一只495岁的吸血鬼,所以她非常喜欢495这个数。

现在小红拿到了一个数组,她认为该数组的“美丽度”为:选两个元素 $a_i $ 和 $a_j (i<j) $,乘积为495的倍数的方案数。

小红可以进行最多1次操作:选择一个元素,使其加1。请你帮小红求出最多1次操作后,数组的最大美丽度。

输入:
第一行输入一个正整数 $ n $,代表每个人数组的大小。

第二行输入 $ n $ 个正整数 $ a_i $,代表数组的元素。

$ 1 \leq n, a_i \leq 400000 $
输出:
一个整数,代表最多一次操作后,数组的最大美丽度。
样例:
4
1 9 55 494
————
4
思路:从495的因数出发,显然一个数存有495因数,那么他乘以其他带有495因数的数结果%495==0,就等价于他们相乘是为495的倍数。
所以先用个数组存495的所有因数可能,然从大到小排序,去重。总共12种可能
然后对于每个数标记它属于哪个可能,即第一次被模除的数的存储下标
用前缀数组和后缀数组,存储和所有状态并传递
首先对于不操作的答案,直接用后缀数组+判断它和其他11种组合是否构成495倍数可以计算出
然后暴力枚举,每个数加+1的情况,首先用前后缀数组把它所有可能都减掉,然后加1,再判断它属于哪种可能
,再次用前后缀数组把他所用可能都加起来,最后取个max

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll a[500000];
ll pre[14][500000];
ll sub[14][500000];
ll d[500000];
int main()
{
	fio();
	ll n;
	cin>>n;
	memset(d,0,sizeof d);
	ll b[60]={0,495,165,99,45,55,33,15,9,11,5,3,1};
	for(ll i=1;i<=n;i++)
	{
		cin>>a[i];
		ll u=a[i];
		for(ll k=1;k<=12;k++)
		{
			pre[k][i]=pre[k][i-1];
		}
		for(ll j=1;j<=12;j++)
		{
			if(a[i]%b[j]==0)
			{
				d[i]=j;
				pre[j][i]++;
				break;
			}
		}
	}
	for(ll i=n;i>=1;i--)
	{
		for(ll k=1;k<=12;k++)
		{
			sub[k][i]=sub[k][i+1];
		}
		for(ll j=1;j<=12;j++)
		{
			if(a[i]%b[j]==0)
			{
				sub[j][i]++;
				break;
			}
		}
	}
	ll ans=0;
	for(ll i=1;i<=n;i++)
	{
		    for(ll j=1;j<=12;j++)
			{
				if((b[j]*b[d[i]])%495==0)
				{
				ans+=sub[j][i+1];
				}
			}
	}
	ll u=ans;
	//cout<<u<<endl;
	ll cnt;
	for(ll i=1;i<=n;i++)
	{
		cnt=u;
			for(ll j=1;j<=12;j++)
			{
				if((b[j]*b[d[i]])%495==0)
				{
					// if(i==1)
					// cout<<j<<endl;
					cnt-=pre[j][i-1]+sub[j][i+1];
				}
			}
			a[i]++;
			ll wz=0;
			for(ll j=1;j<=12;j++)
			{
				if(a[i]%b[j]==0)
				{
					wz=j;
					break;
				}
			}
			for(ll j=1;j<=12;j++)
			{
				if((b[j]*b[wz])%495==0)
				{
					cnt+=pre[j][i-1]+sub[j][i+1];
				}
			}
			ans=max(ans,cnt);
	}
	cout<<ans<<endl;
}

E.博丽神社的巫女(二)

题面:
小红来到了博丽神社,发现博丽神社门口有一个赛钱箱。

这时神社里走出了一个巫女,对小红说:给你一个数组,你可以对任意元素进行任意次“该元素除以2向下取整”的操作,只要你能让这个数组所有元素之和等于100000,你就能拿走赛钱箱里所有的钱,否则你就必须往赛钱箱投十万元,你想和我玩这个游戏吗?

小红很想赚取赛钱箱里的金币,请你帮帮小红。
输入:
第一行输入一个正整数 $ n $ ,代表巫女给小红的数组大小。

第二行输入 $ n $ 个正整数 $ a_i $ ,代表数组的元素。

$ 1 \leq n \leq 100 $

$ 1 \leq a_i \leq 10^5 $

保证所有元素之和 $ S $ 的范围满足 $ 100000 < S < 200000 $

输出:
如果小红必然输掉游戏,请输出-1。
否则输出 $ n $ 个非负整数 $ b_i (0 \leq b_i \leq 10^5) $,分别代表对第 $ i $ 个元素执行 $ b_i $ 次操作。

样例:
2
50000 100000
————
0 1
思路:分组背包变形+set转移数组。首先加和达不到100000直接判-1。
然后考虑如何变形,把原本凑100000,变成是否能减sum-100000,随后这个差值用分组背包变形就好,除了0其他都得复制为一个极大值
首先预处理一个数的所有可能差值与操作次数,vector记住,随后就是分组背包跑一遍,记得set开pair记录操作次数和对谁操作
最后判断dp[sum-100000]是否仍为极大值,如果是,输出-1,否则输出答案

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll a[500];
vector<pair<ll,ll>>g[250];
set<pair<ll,ll>>q[200001];
ll dp[1500000];
ll b[250000];
int main()
{
	fio();
	ll n;
	cin>>n;
	ll sum=0;
	for(ll i=1;i<=n;i++)cin>>a[i],sum+=a[i];
	for(ll i=1;i<=n;i++)
	{
		ll cs=0;
		ll u=a[i];
		while(u)
		{
			u/=2;
			cs++;
			g[i].push_back({cs,a[i]-u});
		}
	}
	if(sum<100000)
	{
		cout<<-1<<endl;
	}
	else 
	{
		sum-=100000;
		for(ll i=1;i<=sum;i++)
		{
			dp[i]=9999999999;
		}
		for(ll i=1;i<=n;i++)
		{
			for(ll j=sum;j>=1;j--)
			{
				for(auto k:g[i])
				{
					ll u=k.first;
					ll f=k.second;
					if(j>=f)
					{
						if(dp[j]>dp[j-f]+1)
						{
							dp[j]=dp[j-f]+1;
							q[j].clear();
							q[j].insert({u,i});
							q[j].insert(q[j-f].begin(),q[j-f].end());
						}
					}
				}
			}
		}
		if(dp[sum]==9999999999)cout<<-1<<endl;
		else 
		{
		for(auto j:q[sum])
		{
			b[j.second]=j.first;
		}
		for(ll i=1;i<=n;i++)cout<<b[i]<<" ";
		cout<<endl;
		}
	}

}
posted @ 2024-11-17 22:04  长皆  阅读(37)  评论(0编辑  收藏  举报