AcWing 5574. 区间分组 AcWing 5573. 叠砖块 AcWing 5575. 改变数值 AcWing acwing154场周赛

本文介绍了如何使用裴蜀定理和01背包算法解决给定大范围整数数组,寻找具有最小gcd值的组合问题,通过动态规划和大根堆数据结构优化求解过程。
摘要由CSDN通过智能技术生成



 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++)
        sum+=i;
    cout<<sum<<endl;
    return 0;
}


简单的前n个数求和。



 

#include<bits/stdc++.h>
using namespace std;
const int N=2000100;
int n;
struct Range
{
	long long l,r;
	bool operator<(const Range &W) const
	{
		return l<W.l;
	}
}a[N];//这里我们进行结构体内的排序 
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		long long l,r;
		cin>>l>>r;
		a[i]={l,r};
		
	}
	sort(a,a+n);
	
	priority_queue<int> heap;
	priority_queue<int> heap1;//定义两个大根堆,分别模拟两个区间 
	bool flag=true;
	//大根堆,堆顶元素是最大值 
	for(int i=0;i<n;i++)
	{
		auto r=a[i];
		if(heap.empty()||heap.top()<r.l)//如果第一个大根堆为空 或者第一个大根堆存在最大的r比最小的l还小,(已经提前对l排序了)证明区间不冲突 
		//则可以加入一个大根堆 
		{
			heap.push(r.r);
		}
		else if(heap1.empty()||(heap1.top()<r.l))
		{//如果第二个大根堆为空 或者第二个大根堆存在最大的r比最小的l还小,(已经提前对l排序了)证明区间不冲突 
		//则可以加入二个大根堆 
			heap1.push(r.r);
		}
		else
		{//否则出现了证明两个大根堆都不可以进去,都会区间重复,跳出循环 
		 	flag=false;
			break;
		}
	}
	if(!flag)//判断 
		cout<<"NO";
	else 
		cout<<"YES";
	return 0;
}



 

裴蜀定理 + 01 背包
由裴蜀定理可知,任意数量的变量的线性系数组合可以凑出所有它们的 gcd的倍数。

为了凑出任意整数,即选出的所有数的 gcd等于 1

此时,整个问题就转化为了从给定的若干个数中选择价值最小的组合,同时使它们的 gcd为 1
即可以用 01 背包求解。

由于 a数组的范围比较大,这里 dp 数组可以用 map。

 

#include <bits/stdc++.h>
using namespace std;
using LL = long long;

const int N = 310;

int n;
int a[N], b[N];
map<int, int> dp; // dp[i][j] : 考虑前 i 个数, 且 gcd({所有选择的数}) 为 j 的最小代价

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++) {
        cin >> b[i];
    }

    dp[0] = 0; // 方便将所有数存到 map 中
    for (int i = 1; i <= n; i++) {
        for (auto [x, y] : dp) {
            int d = __gcd(x, a[i]);
            if (dp.count(d)) {
                dp[d] = min(dp[d], y + b[i]);
            } else {
                dp[d] = y + b[i];
            }
        }
    }

    cout << (dp[1] ? dp[1] : -1) << '\n';

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值