裴蜀定理:若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。

对于此题,若d = 1,则可选的种类一定为无数种,换言,一定有有限个数不能选,求出有多少个不能选就可了。

数据范围为10000,别问我怎么知道的(狗头保命)。​

二维dp做法:



#include <iostream>
using namespace std;

const int N = 105;
bool dp[N][10005];
int w[N];
int n;

int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a;
}

int main()
{
ios::sync_with_stdio(false);
cin>>n;
int d = 0;
for (int i = 1; i <= n; i++) {
cin>>w[i];
d = gcd(d,w[i]);
}

if (d != 1) cout<<"INF\n";
else
{
dp[0][0] = true; // 初始化
for (int i = 1; i <= n; i++) { // 二维完全背包模板
for (int j = 0; j <= 10000; j++) {
dp[i][j] = dp[i-1][j];
if (j >= w[i])
dp[i][j] = dp[i][j] | dp[i][j-w[i]];// 选与不选,恰是1与0,若 w[i]~j都可以选,说明j也可以凑出,为1,那不能凑出的j就是0了
}
}
int ans = 0;
for (int j = 0; j < 10000; j++)
if (!dp[n][j]) // 不能凑出
ans++;
cout<<ans<<endl;
}
return 0;
}


一维dp做法:(补充了一个小tips)



#include <iostream> 
using namespace std;

const int N = 105;
bool dp[10005];
int n;
int w[N];

int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a; // little tips:第一组d = 0 传过来最大公因数就是w[i]
}

int main()
{
ios::sync_with_stdio(false);

cin>>n;
int d = 0;
for (int i = 1; i <= n; i++) {
cin>>w[i];
d = gcd(d,w[i]);
}
if (d != 1) cout<<"INF\n";
else
{
dp[0]= true;
for (int i = 1; i <= n; i++) { // 一维完全背包模板
for (int j = w[i]; j < 10000; j++) {
dp[j] |= dp[j-w[i]]; // 等同二维的解释
}
}
int ans = 0;
for (int j = 0; j < 10000; j++) {
if (!dp[j]) ans++;
}
cout<<ans<<endl;
}
return 0;
}