您的位置:首页 > 其它

E. Mishka and Divisors Codeforces Round #365 (Div. 2) 01背包

2017-11-28 18:29 393 查看
E. Mishka and Diviso
4000
rs

time limit per test
1 second

memory limit per test
256 megabytes

input
standard input

output
standard output

After playing with her beautiful array, Mishka decided to learn some math. After learning how to multiply, divide and what is divisibility, she is now interested in solving the following problem.

You are given integer k and array
a1, a2, ..., an ofn integers. You are to find
non-empty subsequence of array elements such that the product of its elements is divisible byk and it contains minimum possible number of elements.

Formally, you are to find a sequence of indices 1 ≤ i1 < i2 < ... < im ≤ n such that


is divisible byk while
m is minimum possible among all such variants.

If there are more than one such subsequences, you should choose one among them, such that sum of its elements isminimum possible.

Mishka quickly solved this problem. Will you do so?

Input
The first line of the input contains two integers n andk (1 ≤ n ≤ 1 000,1 ≤ k ≤ 1012).

The second line of the input contains n integersa1, a2, ..., an
(1 ≤ ai ≤ 1012) — array elements.

Output
Print single positive integer m in the first line — the number of elements in desired sequence.

In the second line print m distinct integers — the sequence of indices of given array elements, which should be taken into the desired sequence.

If there are more than one such subsequence (e.g. subsequence of minimum possible number of elements and with minimum possible sum of elements), you can print any of them.

If there are no such subsequences, print  - 1 in the only line.

Example

Input
5 60
2 4 6 5 2


Output
3
4 3 1

做这种难题(对于我)真的爽,就算开始一点头绪也没有,但是如果弄懂了会学到很多东西。
这道题01背包,看题目描述的话应该想到类似的解法,就是每个数字只能选一次,让你求出选最优状态,这就类似01背包。
那么怎么规范状态呢。
我们分析一下就可以知道,比如说60的因数是1 2 3 4 5 6 10 12 15 20 30 60这12个数。
设dp【i】【j】的意义为前i个数中选最少的数字相乘为j的倍数的数量。
1.dp[i][j]非递减
2.我们想要得到60,我们可以从剩余11个数字状态转移而来、
3.我们结合01背包,每个数字只有取或者不取,如果不取,那么dp【i】【j】=dp【i-1】【j】,去了就是dp【i】【j】=dp【i-1】【j/gcd(j,s【i】)】
+1(s【i】为给定的数字)
为什么要从dp【i-1】【j/gcd(j,s【i】)】转移而来呢?刚刚说过,dp数组非递减,那么我们要使dp【i】【j】中的j尽可能的小,这样得出的结果才能尽可能的小。
如果j/gcd(j,s【i】)都要比不放要大的话,那么其他的因数自然也就不成立,如果无法达成j/gcd(j,s【i】)这个状态的话,那么其他的因数状态也无法完成,所以这就是正确
的转移方式。
注意,这道题卡常数,非常恶心。在gcd的时候,不要直接gcd(j,s【i】),要先st【i】=gcd(k,s【i】),然后j/gcd(j,st【i】),这样可以少跑一点。
#include<bits/stdc++.h>
using namespace std;
long long s[1008],st[1008];
int pre[1008][10080];
int dp[10008];
long long sum[10008];
vector<long long> factor;
map<long long,int>maped;
int div(long long k)
{
for(long long i=1; i*i<=k; i++)
{
if(k%i==0)
{
factor.push_back(i);
factor.push_back(k/i);
}
}
sort(factor.begin(),factor.end());
return unique(factor.begin(),factor.end())-factor.begin();
}
int main()
{
int n;
long long k;
long long Min=LLONG_MAX;
int pos;
while(scanf("%d%I64d",&n,&k)!=EOF)
{
for(int i=1; i<=n; i++)
{
scanf("%I64d",&s[i]);
st[i]=__gcd(k,s[i]);
if(Min>s[i])
{
Min=s[i];
pos=i;
}
}
if(k==1)
{
printf("%d\n",1);
printf("%d\n",pos);
continue;
}
memset(pre,-1,sizeof(pre));
memset(sum,0x3f,sizeof(sum));
memset(dp,0x3f,sizeof(dp));
dp[0]=sum[0]=0;
factor.clear();
maped.clear();
int len=div(k);
for(int i=0; i<len; i++)
{
maped[factor[i]]=i;
}
for(int i=1; i<=n; i++)
{
for(int j=len-1; j>=1; j--)
{
long long t=__gcd(factor[j],(long long)st[i]);
int pos=maped[factor[j]/t];
if(dp[j]>dp[pos]+1)
{
dp[j]=dp[pos]+1;
sum[j]=sum[pos]+s[i];
pre[i][j]=pos;
}
if(dp[j]==dp[pos]+1&&sum[j]>sum[pos]+s[i])
{
sum[j]=sum[pos]+s[i];
pre[i][j]=pos;
}
}
}
if(dp[len-1]>n)
{
printf("-1\n");
}
else
{
printf("%d\n",dp[len-1]);
int a=n,b=len-1;
while(a>0&&b>0)
{
while(pre[a][b]==-1&&a>0&&b>0)
a--;
printf("%d ",a);
b=pre[a--][b];
}

}
printf("\n");

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐