T1
七夕节刚刚一过就给我来一个秀恩爱节目,玩儿我呢?
我们考虑对T1使用dp,不难发现我们的题目有剩余钱数的大小关系
如果说剩余8块钱,那么剩下的物品肯定都比八块钱贵
换句话说,如果物品价值有序的情况下,剩下的钱的方案数是完全不重叠的,因为前面的物品买了过后剩下的钱只能越来越少
所以我们考虑先对物品的价值进行一次从大到小的排序
然后考虑到dp【j】为已经枚举到当前不选的物品为i,而装的背包体积为j的方案数
那么ans就应该是所有的满足条件的dp求和
我们可以直接进行转移
因为从大到小排序,所以如果我们已经取了第i个物品,就不可能不取剩下的物品
所以剩下的物品一定会取
那么我们再记录一个后缀和sum[i]表示从i到n的价值的求和
所以
dp[j]+=dp[j-a[i]]
每一次加进来新方案就统计贡献并加在ans里面就好了
#include<cstdio>
#include<algorithm>
const int MAXN=1e4+5;
const int MOD =1e9+7;
int dp[MAXN];
int a[MAXN];
int sum[MAXN];
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
//std::freopen("gift.in","r",stdin);
//std::freopen("gift.out","w",stdout);
int n,m;
std::scanf("%d%d",& n,&m);
for(int i=1;i<=n;i++)
{
std::scanf("%d",a+i);
}
std::sort(a+1,a+1+n,cmp);
for(int i=n;i>=1;i--)
{
sum[i]=a[i];
sum[i]+=sum[i+1]%=MOD;
}
int ans=0;
if(sum[1]<=m)
{
ans++;
}
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=m;j>=a[i];j--)
{
dp[j]=(dp[j-a[i]]%MOD+dp[j]%MOD)%MOD;
}
for(int x=m-a[i]+1 ;x<=m-a[i+1];x++)
{
if(x-sum[i+1]>=0)
{
ans=(ans+dp[x-sum[i+1]]%MOD)%MOD;
}
}
}
std::printf("%d\n",ans);
return 0;
}
T2
当m>n的时候,概率是0
然后我们枚举1———n以内所有的m<n的情况.....并且把概率做统计打一张表...就会有神奇的发现
嗯...............
p=(n-m+1)/(n+1)................................
真的挺简单的...............
好的我们讲一下正解
其实就是卡特兰数...............
可以将原问题转化一下,看成是在一个二维平面上行走,+1看成移动(1,0)
-1看成移动(0,1),那么到达(N,M)点且路线又不走到y=x这条直线上方的路线总数就是
答案,这个组合问题很经典,方案数为C(M,M+N)-C(M-1,M+N),所以
可以知道答案就是1-M/(N+1)
。.................
代码简直阿库娅..........
#include<cstdio>
#define LL long long
const double eps=1e-7;
const int MAXN= 1e5+5;
int main()
{
//freopen("fseq.in","r",stdin);
//freopen("fseq.out","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
std::scanf("%d%d",&n,&m);
if(!m)
{
printf("1.000000\n");
continue;
}
if((m>n) || (!n))
{
printf("0.000000\n");
continue;
}
double ans=1.0*(n-m+1)/(n+1);
std::printf("%.6lf\n",ans);
}
return 0;
}
T3
数位dp...........
仍然裸题.................
#include<cstdio>
#include<cstring>
#define LL long long
const int MAXN=21;
LL dp[MAXN][2][2][MAXN];
int digit[MAXN];
int cnt=0;
LL dfs(int dep,int up,int zero,int num)
{
if(!dep)
{
return 1;
}
if(dp[dep][up][zero][num]!=-1)
{
return dp[dep][up][zero][num];
}
LL tmp=0;
for(int t=up==1?digit[dep]:9;t>=0;t--)
{
if(dep<=(cnt-num)/2&&t==digit[cnt-num-dep+1])//
/*
cnt-num-dep+1当前pos ,其实这里是写错了的,但是由于顶了上界只会影响一倍的答案,所以说这里就算写成t==1或者t==2或者t==3....怎么都行,答案不变
当然我们也可以直接在不顶上界的时候,把后面的条件去掉移到上面去再*9.....反正方法多种多样
*/
{
continue;
}
tmp+=dfs(dep-1,up&&(t==digit[dep]),zero&&(!t),num+(zero&&(!t)));
}
return dp[dep][up][zero][num]=tmp;
}
LL solve(LL n)
{
std::memset(dp,-1,sizeof(dp));
LL s=n;
cnt=0;
while(s)
{
digit[++cnt]=s%10;
s/=10;
}
return dfs(cnt,1,1,0);
}
int main()
{
//std::freopen("lucky.in","r",stdin);
//std::freopen("lucky.out","w",stdout);
LL l,r;
std::scanf("%I64d%I64d",&l,&r);
std::printf("%I64d\n",solve(r)-solve(l-1));
return 0;
}
/*
input
1 10
output
10
input
100 2000
output
1620
input
12131 51444
output
31846
*/