题目大意
给出一组数,求出其中共有多少数不能被其他数表示
解题思路
法一:可爱的动态规划
这个思路还是比较好想的(也比较好写?)
有依赖关系的背包,思路这道题是差不多的 填满型01背包
(关于代码) 写起来坑还是比较多的,ans,f记得清零,边界记得写就不说了,转移方程那里
f[j] |= f[j - a[i]];
或符号是一定要加的,举个栗子说明:
以样例为例
a[i] = 3,更新f[3],f[6],f[9],f[12]等等,如果不写或符号, 在a[i]=10更新时会出现 f[12] = f[2] = 0的情况
#include<bits/stdc++.h> using namespace std; const int N = 25050; #define fr(i,n) for(register int i = 1; i <= n; i++) int n,t,m,ans,maxn,a[N],f[N]; int main() { scanf("%d",&t); while(t--){ scanf("%d",&n); fr(i,n) scanf("%d",a + i); sort(a + 1, a + 1 + n); ans = 0; memset(f,0,sizeof(f)); f[0]=1; fr(i,n){ if(f[a[i]]) continue; ans++; f[a[i]] = 1; for(int j = a[i]; j <= a[n]; j++) f[j] |= f[j - a[i]]; } printf("%d ",ans); } return 0; }
法二:
某种筛(原谅数论全忘光的蒟蒻不知道这是哪种)
实际上和背包思路差不多的……然鹅因为是成倍成倍的筛的所以可能快点?emmm
下面是luogu题解大佬 txtxj 的代码(对我真的懒得打)
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int mon[25001]={}; /* mon[i]=0 表示i面值的钱不能被凑出来 mon[i]=1 表示i面值的钱可以被凑出来 mon[i]=2 表示i面值的钱是货币系统中本来就有的钱 */ int coins[101]={};//存钱的面值 int T,n,ans=0; int main() { scanf("%d ",&T); while (T--) { ans=0; memset(mon,0,sizeof(mon)); memset(coins,0,sizeof(coins)); scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&coins[i]); mon[coins[i]]=2; } //把货币系统中的钱标好 sort(coins+1,coins+1+n); for (int i=1;i<=coins[n];i++) { if (mon[i]>0) //如果mon[i]能被凑出来 //那么mon[i+coins[j]]也能被凑出来 { for (int j=1;j<=n;j++) if (i+coins[j]<=coins[n]) //防止数组越界 mon[i+coins[j]]=1; else break; } } for (int i=1;i<=coins[n];i++) if (mon[i]==2) ans++; printf("%d ",ans); } }