codeforces 510 D - Fox And Jumping

题意: 有个人在一维无限平面的原点,现在有n张能力卡,每张卡有一个能力值len和代价co,花费co就能获得到达(x-len)或(x+len)的能力,问这个人能到达所有点的最小代价,或输出不能到达(-1)

n ≤ 300 n \leq 300 n300

前置知识:n个数的翡蜀定理(被喂题的时候同时被喂的这个,几乎就是告诉解法(不是

然而还是不会(你

就是求一个集合他们的共同最大公约数为1的最小代价

能想到这样子每个数就只和他的因数有关

然后我就卡住了 ,去看了题解

1e9之内每个数的质因数的种数最多是9,(因子个数好像是1600)

知道他不多之后就可以用mask dp(??

就是对每个数处理他的mask,然后dp求最小代价

感觉很妙

复杂度 O ( 2 9 × n 2 ) O(2^9 \times n^2) O(29×n2), 实际会更小点

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 310;
const int inf = 1e7;
int n;

int len[N], co[N], m[N];
int f[N][(int)(1 << 9) + 10];

int siz;
int ans = inf;

vector<int> vec;

int dp(int cur, int mask){
    
     //mask dp(
	if(cur == n) {
    
    
		if(mask == (1 << siz) - 1) {
    
    
			return 0;
		}
		return inf;
	} 
	
	if(f[cur][mask] != -1) return f[cur][mask];
	
	f[cur][mask] = inf;
	f[cur][mask] = min(f[cur][mask], dp(cur + 1, mask));
	f[cur][mask] = min(f[cur][mask], dp(cur + 1, mask| m[cur]) + co[cur]);
	
	return f[cur][mask];
}


void getPrimes(int x) {
    
     // 分解质因数
	vec.clear();
	
	for(int i = 2; i <= x / i; ++i) {
    
    
		if(x % i == 0) {
    
    
			vec.push_back(i);
			
			while(x % i == 0) {
    
    
				x /= i;
			}
		}
	}
	
	if(x > 1) {
    
    
		vec.push_back(x);
	}
}

int main() {
    
    
	
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	
	cin >> n;
	for(int i = 0; i < n; ++ i) {
    
    
		cin >> len[i];
	}
	for(int i = 0; i < n; ++ i) {
    
    
		cin >> co[i];
	}
	
	for(int i = 0; i < n; ++i) {
    
     //在选第i数的情况下
		getPrimes(len[i]);
		
		siz = vec.size();
		
		for(int j = 0; j < n; ++ j) {
    
     // 对每个数做mask
			m[j] = 0;
			for(int k = 0; k < siz; ++ k) {
    
    
				if(len[j] % vec[k] != 0)
					m[j] |=  (1 << k);
			}
		}
		
		
		memset(f, -1, sizeof(f)); //初始化-1
		
		int res = dp(0, 0) + co[i];
		
		ans = min(ans, res);
	}
	
	
	if(ans == inf) {
    
    
		cout << -1; 
	}
	else {
    
    
		cout << ans;
	}
	
	return 0;
} 

朋友给了第二种做法:

不太会算复杂度只能说感觉最坏情况好像卡边,但是实际到不了所以很可(大概

O ( n 2 × 1600 ) − − O(n^2 \times 1600) -- O(n2×1600)

但是这里unordered_map遍历好像会有点问题

#include<bits/stdc++.h>
using namespace std;
const int maxn=305;
typedef long long ll;
ll l[maxn],c[maxn];
map<ll,ll>mp;
int main()
{
    
    
    int n;
    while(~scanf("%d",&n)){
    
    
    for(int i=1;i<=n;i++) scanf("%lld",&l[i]);
     for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
      mp.clear();
        mp[0]=0;//gcd(0,x)=x
        //unordered_map<ll,ll>::iterator it; 
        for(int i=1;i<=n;i++) {
    
    
        auto it = mp.begin();
            while(it != mp.end()){
    
         
		    //	cout << it->first << endl;  
                ll a=__gcd(l[i],it->first);
                if(mp.count(a)>0)                         
                    mp[a]=min(mp[a],it->second+c[i]);
                else
                    mp[a]=it->second+c[i];    
				++it;          
            }	
		}
		 
        if(mp[1]==0){
    
    
            printf("-1\n");
        }
        else {
    
    
            printf("%lld",mp[1]);
        }
    }
 
}

猜你喜欢

转载自blog.csdn.net/qq_39602052/article/details/113310108