Codeforces Round 902 (Div. 2, based on COMPFEST 15 - Final补题

Goals of Victory

题目大意:有n支球队,两两之间有一场比赛,我们记录两队的进球数,对于每一队,她们该场比赛的效益为自己队进球数-对手进球数,我们现在已知n-1支队伍的效益,需要求第n支队伍的效益。

思路:在一场比赛中,我们假设a队进了a个球,b队进了b个球,那么对于a队,该场比赛的效益为:w1=a-b,对b队:w2=b-a,故而w1+w2=0.我们进而推广可知所有队伍所有场的比赛累计下来的总效益为0,那么只需要用0减去n-1支队伍的效益和即可。

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		int ans=0;
		for(int i=1;i<n;i++)
		{
			int x;
			scanf("%d",&x);
			ans += x;
		}
		ans = 0-ans;
		printf("%d\n",ans);
	}
	
}

Helmets in Night Light

题目大意:P是村长,现有一个消息需要通过他分享给n个居民,现在有两种分享策略:1.由P分享给其他村民,每分享一个花费为p,2:由村民分享给村民,对于村民i,他最多能分享ai次,每次的费用为bi,求完成分享的最小费用。

思路:首先,这题的最优解肯定是要每次分享的花费都最少。那么就要考虑bi和p的关系,如果bi的最小值大于等于p的话,那么肯定是有P分享给其他人更划算,如果有一部分bi小于P的话,肯定是由这部分人来分享更划算,另外还要注意一点,虽然这部分人中的第一个人需要P来通知,但是这些人之间可以互相通知,并不需要P通知这部分所有人。那么策略就出来了,我们先找出bi的最小值,判断它与p的关系,如果大于等于的话,那么最小费用就是p*n;如果小于的话,那么我们先用一个变量来记录当前有多少人被通知到了,然后去循环村民,如果当前村民的bi小于p,那么这个村名肯定是能够去通知其他人的,我们就要看这个村民有没有被通知到,因为有个记录多少人已经被通知的变量,同时,我们的遍历是按顺序的,所以将当前居民的编号和这个变量比较一下即可,如果没被通知,那么就需要P去通知它,然后记录人数的变量加上他可以通知的人的数量。一旦当前这个人的单次费用大于等于p的时候就没必要再继续循环了,直接让P去通知其他人即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
struct cm
{
	int a,b;
}c[100010];
bool cmp(cm x,cm y)
{
	return x.b<y.b;
}
signed main()
{
	int t;
	scanf("%lld",&t);
	while(t--)
	{
		int n,p;
		scanf("%lld%lld",&n,&p);
		for(int i=1;i<=n;i++) 
		{
			int x;
			scanf("%lld",&x);
			c[i].a=x;
		}
		for(int i=1;i<=n;i++) 
		{
			int x;
			scanf("%lld",&x);
			c[i].b=x;
		}
		sort(c+1,c+1+n,cmp);
		int ans=0;		
		if(c[1].b>=p) ans=n*p,printf("%lld\n",ans);
		else
		{
			int r=0;
			ans=0;
			for(int i=1;i<=n;i++)
			{
				if(c[i].b<p) 
				{
					if(r<i) ans += p,r++;
					if(r+c[i].a<=n) r += c[i].a,ans += c[i].a*c[i].b;
					else ans += (n-r)*c[i].b,r=n;
				}
				else break;
				if(r==n)break;
			}
			//剩下的都由p来通知
			ans += (n-r)*p;
			printf("%lld\n",ans);
		}
		
	}
}

ps:是有爆int的可能的。

Joyboard

题目大意:现有一个空数组a[],其中元素从a[1]-a[n+1],我们需要将这个数组填满,我们能选择的就是将[0,m]中的某个数放到a[n+1]位置,然后a[i]=a[i+1]%i,数组自动被填满。现在我们要求数组最后只能有k种元素,问能否实现,如果可以实现的话有多少种选法。

思路:我们分析一下可以意识到,一旦有一个位置出现0,那么后面一定全都是0,分类讨论一下:

设a[n+1]=x,a[n]=k

a[1]  a[2]...a[k]...a[n-1] a[n] a[n+1]

0      0        0         k       k      x(x>n,对n取模后,值会变化)

a[1]  a[2]...a[k]...a[n-1] a[n] a[n+1]

0      0        0         x       x      x(k<x,取模后值不变)

a[1]  a[2]...a[k]...a[n-1] a[n] a[n+1]

0      0        0         0       0      x(x==n,对n取模后值为0,另外n的倍数也可以实现这个)

a[1]  a[2]...a[k]...a[n-1] a[n] a[n+1]

0      0        0         0       0      0(x==0)

我们可以发现只有这几种情况,所以实际上就讨论出来了。最多只能有三种数,如果要求的种类数>3直接判否,然后如果是3,那么就有m-n种选法,如果这个值小于等于0,那么就判否;如果是2,就有min(n,m)种选法;如果是1,只有一种选法。另外要注意倍数的事情,对于倍数来说,大于1倍的要被算进第二种情况。而且要注意考虑有没有,否则会减多。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m,k;
		scanf("%d%d%d",&n,&m,&k);
		if(k>3) printf("0\n");
		else
		{
			int ans=0;
			if(k==3)
			{
				ans = m-n;
				//要把倍数去掉
				if(m>n) ans -= (m/n-1);
				ans=max(0,ans);
			}
			else if(k==2)
			{
				ans =min(n,m);
				//m有可能小于n,不能直接这么算,否则就会出负的情况
				if(m>n) ans += (m/n-1);//要把一倍减掉
			}
			else
			{
				ans=1;
			}
			printf("%d\n",ans);
		}
	}
}

Effects of Anti Pimples

题目大意:我们给定一个大小为n的数组a[],我们可以选择若干个索引,将该点处染成黑色,然后该索引的倍数索引位置被染成绿色,这种选法的得分为所有黑色和绿色处的值的最大值,我们将所有选法的分数都计算出来求和。

思路:一定要把题目看清楚,每次的分数是最大值,而非和,两者具体到细节上的处理是截然不同的。首先我们预处理出来每个位置如果被选的话,产生的最大值。 实际上就是将从它和它的倍数中取一个最大值,有两种处理方法,一种就是直接进行循环,对每个i去找它的倍数,时间复杂度为nlogn,另一种就是从后往前访问,对于某一个i,如果它的倍数已经出现过,我们就用它的倍数来更新它,实际上跟前一种差不多,不过我这里引入了质数进行优化,我们只用它的质数倍来更新它(我们举个例子来证明正确性,2:4,6,8,...,这里8是2的四倍,8可以将4更新,另外从普遍的角度来考虑,我们对于一个数的合数倍,它一定可以从这个合数中拆出一个质数p,变成k*p倍,那么这个数的k倍肯定也会被这个合数倍更新,而且是先被更新,因为我们是从后往前访问的。)。然后我们来看既然是最大值,那么就要看它在多少中选择中可以作为最大值,对处理好的数组从大到小排序,对于最大的那个数,它可以在2^(n-1)种选择中做最大值,依次类推。

更新a[i]的两种方法:

1.循环

for(int i=1;i<=n;i++)//nlogn
	for(int j=i;j<=n;j+=i) 
		a[i]=max(a[i],a[j]);

2.通过质数累计

vector<int>p;
st[N];
//p装奇数 1-100010
for (int i = 2; i <= n; i ++ )//线性筛质数
{
    if (!st[i]) p.push_back(i); 
    for(auto it:p)
    {
        if(it>n/i) break;
        st[it*i] = true;
        if(i%it==0) break;
	}
}
for(int i=n;i>=2;i--)
{
	if(n-i>=i)//访问过i的倍数,只看奇数倍即可
	{
		s[i]=a[i];
		for(auto it:p)
		{
			int tp=i*it;
			if(tp>n) break;
			else
			{
				s[i]=max(s[i],s[tp]);
			}
		}
	}
	else//没访问过i的倍数
	{
		s[i]=a[i];
	}
}

完整代码:
 

#include<bits/stdc++.h>
using namespace std;
const int N=100010,mod=998244353;
int b[N],a[N];
bool cmp(int x,int y)
{
	return x>y;
}
int main()
{
	b[0]=1;
	b[1]=2;
	for(int i=2;i<=N;i++) b[i]=b[i-1]*2,b[i]%=mod;
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	
	for(int i=1;i<=n;i++)//nlogn
		for(int j=i;j<=n;j+=i) 
			a[i]=max(a[i],a[j]);
	sort(a+1,a+n+1,cmp);
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans += (long long)a[i]*b[n-i]%mod;
		ans %= mod;
	}
	printf("%d",ans);
}

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,根据提供的引用内容,我无法理解你具体想要问什么问题。请提供更清晰明确的问题,我将竭诚为你解答。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [【CodeforcesCodeforces Round 865 (Div. 2) (补赛)](https://blog.csdn.net/t_mod/article/details/130104033)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值