当前位置: 代码迷 >> 综合 >> 数论+dp状压 Codeforces510D Fox And Jumping
  详细解决方案

数论+dp状压 Codeforces510D Fox And Jumping

热度:20   发布时间:2023-12-14 03:44:59.0

传送门:点击打开链接

题意:从n张卡中取出一些卡,使得k1*x1+k2*x2+...+kn*xn=1,问是否能找出这样的卡,并且使费用最低

思路:这里首先必须要知道一个数论知识,gcd(x1,x2,x3..,xn)=1,那么必有k1*x1+k2*x2+...+xn=1。证明就不证明了,但是确实有个特例,gcd(x,y)=1,那么xm+yn=1必有解,是不是很熟悉?就是扩展欧几里德啊!前者也算是扩展欧几里德的扩展把~

然后还有一个数论的知识点,如果x<=1e9,那么x最多只会由9种质数组成

那么如果只有9种质数的话,我们就能考虑状态压缩了。继续分析。。

假如我们枚举其中一张卡,认为必须要选这张,然后求出其所有的质数类型,再循环一遍所有的,如果不能整除某个质数,就在对应的状态上标记为1。

所以现在题目又转换了,现在只需要在n张卡中选出一些卡,使得这些卡的状态的位或结果是整个全集。这部分可以利用状态压缩枚举来完成,后面步骤就很类似背包问题了。

题目通过了数论,最后完全转换成了比较熟悉的dp问题,,而且提出了如何处理从多个数字中选出一些使得任意组合能组成数字1这个问题,实在是好题~

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck printf("fuck")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;const int MX = 300 + 5;
const int INF = 0x3f3f3f3f;int n;
int dp[1 << 10];
int A[MX], cost[MX], prime[MX];int main() { //FIN;while(~scanf("%d", &n)) {for(int i = 1; i <= n; i++) {scanf("%d", &A[i]);}for(int i = 1; i <= n; i++) {scanf("%d", &cost[i]);}int ans = INF;for(int i = 1; i <= n; i++) {memset(dp, INF, sizeof(dp));int rear = 0, t = A[i];for(int j = 2; (LL)j * j <= A[i]; j ++) {if(t % j == 0) {prime[rear++] = j;while(t % j == 0) t /= j;}}if(t != 1) prime[rear++] = t;dp[0] = 0;for(int j = 1; j <= n; j++) {int x = 0;for(int k = 0; k < rear; k++) {if(A[j] % prime[k]) x ^= 1 << k;}for(int S = 0; S < (1 << rear); S++) {if(dp[S] < INF) dp[S | x] = min(dp[S | x], dp[S] + cost[j]);}}ans = min(ans, dp[(1 << rear) - 1] + cost[i]);}printf("%d\n", ans == INF ? -1 : ans);}return 0;
}


  相关解决方案