您的位置:首页 > 其它

codeforces 510D Fox And Jumping

2015-02-05 21:07 295 查看
题意 大概是 你现在在X坐标轴上0点 ,现在你有N个魔法,第i 个魔法的魔法效果 就是 让你学会 跳 L[ i ] 这么长的距离,学习这个魔法 花费 C[i],

现在 你想花费最少的钱,使得你能够跳到 X轴上的整数任意位置。X轴 正负都无穷远

首先想到 如果能跳 1 这个单位长度 就能 跳到任意位置了,我是猜到 需要 所有的跳的距离 的 L 的 公约数 要为 1才能,具体证明应该是中国剩余定理能证明,其实我不会。

我首先想到的是,用传统的 DP 和 分解质因子 状压 做

因为 10^9里面 质因子最多9个,那么 直接可以 用 dp[i][j] 分别表示 要选 第i个魔法 其中 公约数质因子 含有那些的状态

复杂度是 n^2*512 的 首先枚举第i个魔法 ,然后枚举1- i-1 中 状态为 K的 进行转移

我的博客里面还有另外一份 用 map dp 的, 那种思想很简单很暴力,也很好写

代码如下

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
#define INFF 0x3fffffff

int l[310],c[310];
vector<int>p[310];
int dp[310][(1<<9)];
int gcd(int x,int y)
{
if(y==0)
return x;
return gcd(y,x%y);
}
int fun(int j,int k)
{
int res=1;
int id=0;
while(k)
{
if(k&1)
{
res*=p[j][id];
}
k=k>>1;
id++;
}
return res;
}
int fun1(int i,int tmp)
{
int len=p[i].size();
int res=0;
for(int j=len-1;j>=0;j--)
{
res=res*2;
if(tmp%p[i][j]==0)
{
res+=1;
}
}
return res;
}
void make(int i)
{
int tmp=l[i];
for(int j=2;j*j<=l[i];j++)
{
if(tmp%j==0)
{
while(tmp%j==0)
{
tmp=tmp/j;
}
p[i].push_back(j);
}
}
if(tmp>1)
p[i].push_back(tmp);
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&l[i]);
p[i].clear();
}
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
make(i);

for(int i=0;i<=n;i++)
for(int j=0;j<(1<<9);j++)
dp[i][j]=INFF;
for(int i=1;i<=n;i++)
{
int t1=p[i].size();
dp[i][(1<<t1)-1]=min(dp[i][(1<<t1)-1],c[i]);
for(int j=1;j<i;j++)
{
int t2=p[j].size();
for(int k=0;k< ((1<<t2));k++)
{
int tmp=fun(j,k);
tmp=gcd(l[i],tmp);
int x=fun1(i,tmp);
dp[i][x]=min(dp[i][x],dp[j][k]+c[i]);
}
}
}
int ans=INFF;
for(int i=1;i<=n;i++)
ans=min(dp[i][0],ans);
if(ans>=INFF)
printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: