大意: 给定$n$元素序列$a$, 现在想要让$gcd(a_1,a_2,...,a_n)=1$. 对于每个$a_i$可以除以一个不超过$k$的因子, 代价为$e_i$, 假设一共选择了$x$个元素去除, 代价和为$y$, 求$xy$的最小值.

设$g=gcd(a_1,a_2,...,a_n)=p_1^{\alpha_1}p_2^{\alpha_2}\cdots p_r^{\alpha_r}$, 有$1\le r \le 11$

我们考虑最优解的结构, 对于一个数$a_i$, 它的某个素因子$p_k$想要对答案产生贡献则必须将$p_k$全部除去, 所以每个数都可以用一个二进制状态表示, 并且显然最优解至多选择$r$个$a_i$. 这样的话就可以得到暴力代码, 转移复杂度是$O(nr2^{2r})$, 显然过不去

//dp[i][j][k] 表示前i个数取j个数状态为k时的最小值
memset(dp,0x3f,sizeof dp);
dp[0][0][0]=0;
REP(i,1,n) {
//预处理出每个状态需要除的数num
REP(j,1,S) if (num[j]<=k) {
REP(x,0,S) {
REP(t,1,r) {
chkmin(dp[i][t][x|j],dp[i-1][t-1][x]+a[i].e);
}
}
}
}
ll ans = INF;
REP(i,1,r) if (dp[n][i][S]!=INF) ans=min(ans, dp[n][i][S]*i);

下面考虑优化

  • 对于每个$a_i$, 对于它不在$g$内的素因子直接除去不考虑, 打表发现这样不同的$a_i$不超过M=12000
  • 对于每个不同的$a_i$只取$e$前$r$小的, 并且每个状态只至多转移$r$次
  • 枚举补集的子集, 可将$2^{2r}$优化为$3^r$

这样转移的复杂度就为$O(Mr2^r+r^23^r)$

最后要注意最大素因子是$O(max{a_i})$的, 要开long long 存!!

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <math.h>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <string.h>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
//head const int N = 1e6+10; int n, w[N];
ll k, g;
struct _ {
ll a;
int e;
bool operator < (const _ &rhs) const {
return e<rhs.e;
}
} a[N];
vector<ll> A;
map<ll,int> vis;
ll dp[2][12][1<<11], num[1<<11]; void factor(ll g) {
int mx = sqrt(g+0.5);
REP(i,2,mx) if (g%i==0) {
A.pb(i);
while (g%i==0) g/=i;
}
if (g>1) A.pb(g);
} void chkmin(ll &x, ll y) {x=min(x,y);} int main() {
scanf("%d%lld", &n, &k);
REP(i,1,n) scanf("%lld", &a[i].a),g=gcd(g,a[i].a);
if (g==1) return puts("0"),0;
REP(i,1,n) scanf("%d", &a[i].e);
sort(a+1,a+1+n);
factor(g);
int r = A.size(), S = (1<<r)-1, cur = 0;
memset(dp[0],0x3f,sizeof dp[0]);
dp[0][0][0]=0;
REP(i,1,n) {
ll b = 1;
REP(j,0,r-1) if (a[i].a%A[j]==0) {
ll t = 1;
while (a[i].a%A[j]==0) a[i].a/=A[j],t*=A[j];
num[1<<j] = t;
b *= t;
}
if (++vis[b]>r) continue;
num[0] = 1;
cur ^= 1;
memcpy(dp[cur],dp[cur^1],sizeof dp[cur]);
REP(j,1,S) {
num[j] = num[j^j&-j]*num[j&-j];
if (num[j]>k) continue;
if (++vis1[j]>r) continue;
ll x = ~j&S;
PER(t,0,r-1) {
for (int y=x; y; y=(y-1)&x) if (dp[cur^1][t][y]!=INF) {
chkmin(dp[cur][t+1][y^j],dp[cur^1][t][y]+a[i].e);
}
chkmin(dp[cur][t+1][j],dp[cur^1][t][0]+a[i].e);
}
}
}
ll ans = INF;
REP(i,1,r) if (dp[cur][i][S]!=INF) {
ans = min(ans, dp[cur][i][S]*i);
}
printf("%lld\n", ans==INF?-1:ans);
}

Professional layer CodeForces - 1103D (状压,gcd)的更多相关文章

  1. Vladik and cards CodeForces - 743E (状压)

    大意: 给定序列, 求选出一个最长的子序列, 使得任选两个[1,8]的数字, 在子序列中的出现次数差不超过1, 且子序列中相同数字连续. 正解是状压dp, 先二分转为判断[1,8]出现次数>=x ...

  2. Keyboard Purchase CodeForces - 1238E (状压)

    大意: 给定串$s$, 字符集为字母表前$m$个字符, 求一个$m$排列$pos$, 使得$\sum\limits_{i=2}^n|{pos}_{s_{i-1}}-{pos}_{s_{i}}|$最小. ...

  3. CodeForces 11D(状压DP 求图中环的个数)

    Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycle with no re ...

  4. Clear The Matrix CodeForces - 903F (状压)

    大意: 给定4行的棋盘以及4种大小的正方形方块, 每种各有一定花费, 每次可以选一种方块放在棋盘上, 棋盘对应格子全变为'.', 求最少花费使得棋盘全部变成'.' 状压基本操作练习, 状态取12位, ...

  5. Pollywog CodeForces - 917C (状压)

    链接 大意: 一共n个格子, 初始$x$只蝌蚪在前$x$个格子, 每次最左侧的蝌蚪向前跳, 跳跃距离在范围[1,k], 并且每只蝌蚪跳跃都有一定花费, 有$q$个格子上有石头, 若有蝌蚪跳到某块石头上 ...

  6. Codeforces 678E 状压DP

    题意:有n位选手,已知n位选手之间两两获胜的概率,问主角(第一个选手)最终站在擂台上的概率是多少? 思路:一看数据范围肯定是状压DP,不过虽然是概率DP,但是需要倒着推:我们如果正着推式子的话,初始状 ...

  7. Codeforces 8C 状压DP

    题意:有个人想收拾行李,而n个物品散落在房间的各个角落里(n < 24).现在给你旅行箱的坐标(人初始在旅行箱处),以及n个物品的坐标,你一次只能拿最多两个物品,并且拿了物品就必须放回旅行箱,不 ...

  8. Codeforces 1215E 状压DP

    题意:给你一个序列,你可以交换序列中的相邻的两个元素,问最少需要交换多少次可以让这个序列变成若干个极大的颜色相同的子段. 思路:由于题目中的颜色种类很少,考虑状压DP.设dp[mask]为把mask为 ...

  9. Crisp String CodeForces - 1117F (状压)

    #include <iostream> #include <algorithm> #include <cstdio> #include <math.h> ...

随机推荐

  1. linux常用命令:gzip 命令

    减 少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间.gzip是在Linux系统中经常使用的一个对文件进 行压缩和解压缩的命令,既方便又好用.gzip不仅可 ...

  2. [转载]C#异步调用四大方法详解

    C#异步调用四大方法是什么呢?C#异步调用四大方法的使用是如何进行的呢?让我们首先了解下什么时候用到C#异步调用: .NET Framework 允许您C#异步调用任何方法.定义与您需要调用的方法具有 ...

  3. SVN版本服务器搭建

    windows:        https://blog.csdn.net/lu1024188315/article/details/74082227 SVN 的下载地址如下 http://torto ...

  4. linux环境下安装tomcat6

    1)下载apache-tomcat-6.0.10.tar.gz 2)#tar -zxvf apache-tomcat-6.0.10.tar.gz ://解压 3)#cp -R apache-tomca ...

  5. 怎么解决深入学习PHP的瓶颈

    PHP给学习者的感觉是:初学的时候很容易,但是学了2-3年,就深刻感觉遇到了瓶颈,很难深入,放弃又可惜.所谓"鸡肋,食之无味弃之可惜"的感觉很是贴切. 经常会有这种感觉:不学,看似 ...

  6. Charles手机端抓包--证书

    应用测试: Charles通过无线对手机进行抓包 测试系统: ubuntu 16.04 LTS 测试手机: IOS 10.3(14E277) Charles版本: Charles 4.1.4 手机证书 ...

  7. Android实践项目汇报总结(上)修改

    微博客户端的设计与实现(上) 第一章 绪论 1.1课题背景 微博可以说是时下最受人们所喜爱的一种社交方式,它是一种通过关注机制分享简短实时信息的广播式的社交网络平台.通过微博我们可以了解最新的时事新闻 ...

  8. linux内核分析 第五周

    一.实验相关 1.下载老师最新的menu文件,并在其中添加上周所编写的代码,并运行 下载 添加 运行 2.gdb调试跟踪 gdb设置跟踪文件(先进入linux-3.18.6所在的文件) gdb设置断点 ...

  9. Android 自动化测试介绍

    1 介绍: 风格: 3, 4,

  10. Go第七篇之规范的接口

    接口本身是调用方和实现方均需要遵守的一种协议,大家按照统一的方法命名参数类型和数量来协调逻辑处理的过程. Go 语言中使用组合实现对象特性的描述.对象的内部使用结构体内嵌组合对象应该具有的特性,对外通 ...