题目: http://www.codeforces.com/contest/261
A:简单贪心,选qi最小的discount重复使用,按价格从大到小的顺序即为最优,选qi最小的discount可以使优惠次数最多,从大到小的顺序保证尽可能的使贵的商品免费
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf=1<<28;
int a[100010];
int main() {
int m,n,x,y=inf;
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d",&x);
y=min(y,x);
}
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
ll ans=0;
for (int i = n - 1; i >= 0; i -= y + 2) {
for (int j = 0; j <= min(y - 1, i); j++) {
ans += a[i - j];
}
}
printf("%I64d\n",ans);
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf=1<<28;
int a[55];
double dp[55][55],f[55][55][55];
double A(int n){
if(n<0) return 0;
double ans=1;
for(int i=2;i<=n;i++){
ans*=i;
}
return ans;
}
int cmp(int x,int y){
return x>y;
}
int main() {
int n,p;
scanf("%d",&n);
int sum=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
scanf("%d",&p);
if(sum<=p){
printf("%.10lf\n",(double)n);
return 0;
}
dp[0][0]=1;
double ans=0;
for(int i=0;i<n;i++){
for(int j=n;j>0;j--){
for(int k=0;k<=p;k++){
if(k>=a[i])
dp[j][k]+=dp[j-1][k-a[i]];
}
}
}
for(int i=0;i<n;i++)
f[0][0][i]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=p;j++)
for(int k=0;k<n;k++){
if(j>=a[k])
f[i][j][k]=dp[i][j]-f[i-1][j-a[k]][k];
else f[i][j][k]=dp[i][j];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=p;j++){
for(int k=0;k<n;k++){
if(j+a[k]>p){
ans+=A(i)*f[i][j][k]*A(n-i-1)*i;
}
}
}
}
printf("%.10lf\n",ans/A(n));
}
C:首先打一下表找规律,sum=2^(bit_count(m+1)-1) (证明不会) ,那么如果t不上2的整数次幂,答案为0;否则就是求2到m+1中有多少个数的bit_count=p (2^(p-1)=t) ,可以预处理一个dp[i][j],表示i位有j个1的数字个数(2进制),然后按位统计一下
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int inf=1<<28;
ll dp[55][55];
ll solve(ll n,int p)
{
ll ans=0;
int P=p;
for(int i=50;i>0;i--){
if(((n>>i)&1)){
ans+=dp[i][p];
p--;
}
}
if((p==0&&(n&1)==0)||(p==1&&(n&1)))
ans++;
if(P==0||P==1) ans--;
return ans;
}
int main()
{
ll m,t;
scanf("%I64d%I64d",&m,&t);
int flag=0,p=1;
while(t>1){
if(t%2){
flag=1;break;
}
t/=2;
p++;
}
if(flag){
printf("0\n");
return 0;
}
dp[0][0]=1;
for(int i=1;i<=50;i++)
for(int j=0;j<=i;j++){
dp[i][j]=dp[i-1][j];
if(j) dp[i][j]+=dp[i-1][j-1];
}
printf("%I64d\n",solve(m+1,p));
}