Educational Codeforces Round 135 (Rated for Div. 2) - E. Red-Black Pepper

exgcd

Problem - E - Codeforces

题意

n(n<=3105) 个菜,每个菜可以加红辣椒或黑辣椒,分别可以获得 c[i],d[i] 分;

m(m<=3105) 个商店,第 i 个商店包含 xi,yi, 表示只打包卖红辣椒 a 个,黑辣椒 b 个,即必须有 x,y>=0, 且 ax+by=n

求若分别去这 m 个商店买辣椒,分别最多能获得多少分

思路

  1. 假设全部加黑辣椒,求出当前的答案 ans=d[i] (不用管是否满足有解)
  2. e[i]=c[i]d[i], 从大到小排序,求出前缀和 s[i],若能加 k 个红辣椒,则就取前 k 个
  3. 用 exgcd 解出一组解 x0,y0, 且 x0 为最小非负整数解,此时若 y0<0 则返回 -1
  4. d=gcd(a,b), 通解为 x=x0+tbd, 并找出满足 y>=0 的最大的 xmx
  5. 由于 s[i] 是单峰的,三分即可
  6. 也可以找到峰,求峰两侧的 x 对应的最大值即可(详细见代码)

代码

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;


const int N = 3e5 + 10;
int n;
ll c[N], s[N];
ll ans;
int idx;
ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	ll xx, yy;
	ll d = exgcd(b, a % b, xx, yy);
	x = yy, y = xx - a / b * yy;
	return d;
}

ll solve(ll a, ll b)
{
	ll x, y;
	ll d = exgcd(a, b, x, y);
	if (n % d)
		return -1;
	x *= n / d, y *= n / d;
	ll bb = b / d;
	x %= bb;
	if (x < 0)
		x += bb;
	y = (n - x * a) / b;
	if (y < 0)
		return -1;
	int l = x, r = (n - l * a) / (bb * a) * bb + l;
	if (l * a >= idx)
		return s[l*a] + ans;
	if (r * a <= idx)
		return s[r*a] + ans;
	int lim = (idx - l * a) / (bb * a) * bb + l;
	return max(s[lim * a], s[(lim + bb) * a]) + ans;
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		int x, y;
		cin >> x >> y;
		c[i] = x - y;
		ans += y;
	}
	sort(c + 1, c + n + 1, greater<ll>());
	for (int i = 1; i <= n; i++)
	{	
		s[i] = s[i-1] + c[i];
		if (c[i] >= 0)
			idx = i;
	}
	int q;
	cin >> q;
	while(q--)
	{
		int a, b;
		cin >> a >> b;
		cout << solve(a, b) << endl;
	}
    return 0;
}
posted @   hzy0227  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示