Codeforces Round 108 (Div. 2) ABCD

A.Red and Blue Beans

肯定是少的球带多的球,一个带多个。比如2 7 3 肯定是1 3 和1 4这样
所以用大的/小的上取整,判断这个数是否小于等于d即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int a,b,c;
		cin>>a>>b>>c;
		if((max(a,b)+min(a,b)-1)/min(a,b)-1>c)puts("NO");
		else puts("YES");
	}
	return 0;
}

B.The Cake Is a Lie

试了几个不同路径,发现费用都是一样的,所以直接算从原点一直走到右边,再从右边垂直往下的费用即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int a,b,c;
		cin>>a>>b>>c;
		int ans=a-1+(b-1)*a;
		if(ans!=c)puts("NO");
		else puts("YES");
	}
	return 0;
}

C.Berland Regional(前缀和)

先分别把每个学校的学生存起来,然后对每个学校的学生大到小排序,算个前缀和。然后枚举k。可以发现只有k小于等于这个学校人数的时候才有贡献,大于了贡献为0。当前学校学生人数为tot。则当前枚举到k的贡献为
s u m [ t o t − t o t % k ] sum[tot-tot\%k] sum[tottot%k]
然后把这个k的贡献累加到总的这个k的贡献即可。
具体看代码,就是暴力算就行。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
#define pii pair<int,int>
ll ans[N];
vector<ll>v[N],sum[N];
pii s[N];
bool cmp(int x,int y)
{
	return x>y;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&s[i].first);
			v[i].clear();
			sum[i].clear();
			ans[i]=0;
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&s[i].second);
			v[s[i].first].push_back(s[i].second);
		}
		for(int i=1;i<=n;i++)
		{
			sort(v[i].begin(),v[i].end(),cmp);
			sum[i].resize(v[i].size()+1);
		}
		for(int i=1;i<=n;i++)
		{
			if(v[i].empty())continue;
			sum[i][0]=0;
			for(int j=0;j<v[i].size();j++)sum[i][j+1]=sum[i][j]+v[i][j];
		}
		for(int i=1;i<=n;i++)
		{
			if(v[i].empty())continue;
			for(int k=1;k<=v[i].size();k++)
			{
				int tot=v[i].size();
				int left=tot%k;
				ans[k]+=sum[i][tot-left];
			}
		}
		for(int i=1;i<=n;i++)printf("%lld ",ans[i]);
		puts("");
	}
	return 0;
}

D.Maximum Sum of Products(区间dp)

f [ i ] [ j ] f[i][j] f[i][j]表示把区间i-j逆转后的乘积和。
f [ i ] [ [ j ] = f [ i + 1 ] [ j − 1 ] + a [ j ] ∗ b [ i ] + a [ i ] ∗ b [ j ] f[i][[j]=f[i+1][j-1]+a[j]*b[i]+a[i]*b[j] f[i][[j]=f[i+1][j1]+a[j]b[i]+a[i]b[j]
这个 n 2 n^2 n2就可以算出来
再算个前缀乘积和 ,后缀乘积和。
然后就暴力枚举反转区间i-j的答案即可。

#include<bits/stdc++.h>
using namespace std;
const int N=5000+10;
typedef long long ll;
#define pii pair<int,int>
ll f[N][N],p[N],s[N],a[N],b[N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++)scanf("%lld",&b[i]),f[i][i]=a[i]*b[i],p[i]=p[i-1]+a[i]*b[i];
	for(int i=n;i>=1;i--)s[i]=s[i+1]+a[i]*b[i];
	for(int len=2;len<=n;len++)
		for(int i=1;i+len-1<=n;i++)
		{
			int j=i+len-1;
			if(len==2)f[i][j]=a[j]*b[i]+a[i]*b[j];
			else f[i][j]=f[i+1][j-1]+a[j]*b[i]+a[i]*b[j];
		}
	ll ans=0;
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j++)ans=max(p[i-1]+s[j+1]+f[i][j],ans);
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值