gym102460 F Miss Sloane 2019ICPC Taipei

https://codeforces.com/gym/102460

Learn from the bidding process

First of all, the formula in the question can be observed and found to be i*sum{e[i]}, that is, the number you choose is the sum of these e[i] multiplied by the selected number

Then the maximum initial gcd is 1e12, then the maximum is 11 prime factors. Our goal is to get rid of the numbers of all prime factors in these gcd, and because a number can only be divided by once, so if we want to Divide by operation, this number must be able to divide some prime factors in gcd to 0, otherwise it is white

So we can choose no more than 11 numbers to divide by operation, then we can perform state pressure DP, dp[i][s] means selecting i numbers for elimination display, the elimination quality factor is s, and s is 1 quality The smallest sum of e whose factors have been eliminated. Then in the preprocessing, for each member's a[i], find out which gcd he can eliminate to 0, and the divisor used is within k, add his e[i] to a heap in the corresponding state, Since 11 members can be eliminated at most, then there are 2^11 situations to eliminate, and each situation only needs to save up to 11 members.

Then the smaller elimination value of 2^11 * 11 is available, but a member can only eliminate one time, so he can only use one gcd that he can eliminate, a bit like a group backpack, we make him a state pressure DP , For each state to be eliminated, it is enough to enumerate all states once, and the complexity is 11*2^22

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;

const int maxl=1e6+10;
const ll inf=1e15;

int n,tot;
ll k,g,ans;
ll e[maxl],p[12],b[12],ck[1<<11];
struct node
{
	ll val,e;int id;
}a[maxl];
ll dp[12][1<<11];
priority_queue<pr> c[1<<11];
vector<int> d[maxl];

inline bool cmp(const node &x,const node &y)
{
	if(x.val==y.val)
	{
		if(x.e==y.e)
			return x.id<y.id;
		return x.e<y.e;
	}
	return x.val<y.val;
}

inline void prework()
{
	scanf("%d%lld",&n,&k);
	g=0;tot=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i].val);
		g=__gcd(g,a[i].val);
	}
	for(ll i=2;i*i<=g;++i)
	if(g%i==0)
	{
		p[++tot]=i;
		while(g%i==0)
			g/=i;
	}
	if(g>1)
		p[++tot]=g;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&e[i]);
		ll a2=a[i].val;
		for(int j=1;j<=tot;j++)
			while(a2%p[j]==0)
				a2/=p[j];
		a[i].val/=a2;a[i].e=e[i];a[i].id=i;
	}
	sort(a+1,a+1+n,cmp);
}

inline void mainwork()
{
	if(tot==0)
	{
		ans=0;
		return;
	}
	ck[0]=1;int l=1,r;
	while(l<=n)
	{
		r=l;
		while(a[r].val==a[l].val && r<=n)
			++r;
		for(int i=1;i<=tot;i++)
		{
			b[i]=1;
			while(a[l].val%p[i]==0)
			{
				b[i]*=p[i];
				a[l].val/=p[i];
			}
			for(int j=0;j<(1<<(i-1));j++)
				ck[j|(1<<(i-1))]=ck[j]*b[i];
		}
		for(int i=0;i<(1<<tot);i++)
		if(ck[i]<=k)
			for(int j=l;j<=min(r-1,l+tot-1);j++)
			{
				c[i].push({a[j].e,a[j].id});
				if((int)c[i].size()>tot)
					c[i].pop();
			}
		l=r;
	}
	for(int i=0;i<(1<<tot);i++)
	while(c[i].size())
	{
		d[c[i].top().second].push_back(i);
		c[i].pop();
	}
	for(int i=0;i<=tot;i++)
		for(int j=0;j<(1<<tot);j++)
			dp[i][j]=inf;
	ans=inf;dp[0][0]=0;
	for(int i=1;i<=n;i++)
		for(int k=tot;k>=1;k--)
			for(int s:d[i])
				for(int j=(1<<tot)-1-s;;j=(j-1)&~s)
				{	
					dp[k][j|s]=min(dp[k-1][j]+e[i],dp[k][j|s]);
					if(!j) break;
				}
	for(int i=1;i<=tot;i++)
		ans=min(i*dp[i][(1<<tot)-1],ans);
	if(ans==inf)
		ans=-1;
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

 

Guess you like

Origin blog.csdn.net/liufengwei1/article/details/108543149