题解
1、小红不想做鸽巢原理
思路:贪心问题(个人理解,不知道怎么应用鸽巢原理)
1、应为每次可以取k个,所以最后每个颜色色剩余 a[i]%k
个小球, 总的剩余球数为sum
个
2、这是后我们想让剩余的颜色种类数尽量的少,并且剩余小球的个数为sum
个,这时候我们想到,
让剩余颜色中,小球个数最多的剩余,这样就会让剩余的颜色种类最少。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long LL;
int a[N];
LL sum;
int main()
{
int n; cin>>n;
LL k; cin>>k;
for(int i = 0; i<n; i++)
{
scanf("%d",&a[i]);
a[i] %= k;
sum += a[i];
}
sum %= k;//最后剩余的小球个数
sort(a,a+n);
int cnt = 0,res = 0;
for(int i = n-1; i>=0; i--)
{
if(cnt>=sum)//当我们想让剩余小球的个数,超过实际剩余个数的时候,就结束
{
cout<<res<<endl;
break;
}
else
{
cnt += a[i];
res++;//颜色种数增加
}
}
return 0;
}
2、小红不想做完全背包(easy)
#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
typedef long long LL;
int a[N];
map<int,int> mp;
int main()
{
int n,p;
cin>>n>>p;
for(int i = 0; i<n; i++)
{
cin>>a[i];
a[i]%=3;
mp[a[i]] = 1;
}
if(mp[0])
{
cout<<1<<endl;
}
else if(mp[1] && mp[2])
{
cout<<2<<endl;
}
else
{
cout<<3<<endl;
}
return 0;
}
3、小红不想做完全背包 (hard)
思路:
1、dp问题,我们用f[i]表示,选取的物品价值之和模p为i的集合,f[i] 的值为最少的物品数量
2、我们想一想如何转移,有两种方法:一种是根据当前的状态,转移下一种状态 ;另一种是根据上一种状 态转移出来现在的状态;
3、初始化问题,x = a[i]%p, f[x]
最少肯定是一件,其余的初始化为正无穷。
4、两种转移方法:
f[j] = min(f[j], f[(j-a[i]+p % p)]+1);
int ne = (a[i]+j)%p; f[ne] = min(f[ne], f[j] + 1);
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 2005;
const long long INF = 1e18;
int a[N];
long long f[N];
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
memset(f,0x3f,sizeof f);
int n,p;
cin>>n>>p;
for(int i = 0; i<p; i++) f[i] = INF;
for(int i = 1; i<=n; i++)
{
cin>>a[i];
a[i] %= p;
f[a[i]] = 1;
}
for(int i = 1; i<=n; i++)
{
for(int j = p - 1; j >= 0; j--)
{
//f[j] = min(f[j], f[(j-a[i]+p % p)]+1);
int ne = (a[i]+j)%p;
f[ne] = min(f[ne], f[j] + 1);
}
}
cout<<f[0]<<endl;
return 0;
}