机房模拟20180819

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
*/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值