您的位置:首页 > 其它

Codeforces 703E Mishka and Divisors 离散化+DP

2017-08-15 17:59 302 查看
题意:给出长度为n的序列a,子序列合法:子序列中每个元素相乘后得到的乘积能被k整除

n<=1e3,k,a[i]<=1e12.找到长度最小的合法子序列(若长度最小的有多个,输出子序列和最小的)

 

设f[i][d]为 前i个数中选出乘积为d的倍数需要的最少个数.

f[i][d]=min(f[i-1][d],f[i-1][d/gcd(d,a[i])]+1)  (f[i][x]<=f[i][px])
离散化第二维,因为d每次都转移到自己的某个因子中.最坏情况下只有6720个因子..

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> ii;
const int N=1e3+5;
vector<ll> v;
map<ll,int>id;
ii f
[8000];
ll n,k,m;
void init()
{
v.clear();
for(ll i=1;i*i<=k;i++)
{
if(k%i==0)
{
v.push_back(i);
if(i*i!=k)
v.push_back(k/i);
}
}
sort(v.begin(),v.end());
m=v.size()-1;
id.clear();
for(int i=0;i<=m;i++)
id[v[i]]=i;
}
ll a
,b
;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
while(cin>>n>>k)
{
init();
for(int i=1;i<=n;i++)
scanf("%I64d",&a[i]),b[i]=gcd(a[i],k);
if(k==1)
{
puts("1");
printf("%d\n",min_element(a+1,a+1+n)-a);
continue;
}
for(int j=1;j<=m;j++)
f[0][j]=ii(n+1,0);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j]=f[i-1][j];
int pre=id[v[j]/gcd(v[j],b[i])];
ii t=ii(f[i-1][pre].first+1,f[i-1][pre].second+a[i]);
f[i][j]=min(f[i][j],t);
}
}
if(f
[m].first>n)
puts("-1");
else
{
printf("%d\n",f
[m].first);
for(int i=n;i>=1;i--)
{
if(f[i][id[k]]!=f[i-1][id[k]])
{
printf("%d ",i);
k/=gcd(k,b[i]);
}
}
}
printf("\n");
}
return 0;
}


ps:

a[i]较大,令b[i]=gcd(a[i],k) 求gcd(a[i],v[j])时,将a[i]用b[i]代替不影响结果 (第一步只是排除掉a[i]中不含k素因子的因子).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: