zoukankan      html  css  js  c++  java
  • 【BZOJ1044】[HAOI2008]木棍分割 二分+DP

    【BZOJ1044】[HAOI2008]木棍分割

    Description

      有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007。。。

    Input

      输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000.

    Output

      输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.

    Sample Input

    3 2
    1
    1
    10

    Sample Output

    10 2

    HINT

    两种砍的方法: (1)(1)(10)和(1 1)(10)

    题解:第一问直接二分答案即可,第二问显然是DP。

    为了方便转移,我们需要对于每个位置i,求出pre[i]表示i的上一个砍断位置最远是多少,这个用双指针法和二分都可以搞。然后设f[i][j]表示在前i个连接处砍了j刀的方案数,那么用前缀和优化转移即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int P=10007;
    int n,m,ans,len;
    int v[50010],s[50010],f[2][50010],sf[2][50010],pre[50010];
    
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    bool solve(int x)
    {
    	int i,sum=0,last=0;
    	for(i=1;i<=n&&sum<=m;i++)	if(s[i]-s[last]>x)
    	{
    		if(last==i-1)	return 0;
    		last=i-1,sum++;
    	}
    	sum++;
    	if(sum>m)	return 0;
    	return 1;
    }
    int main()
    {
    	n=rd(),m=rd()+1;
    	int i,j,k,l=0,r=0,mid;
    	for(i=1;i<=n;i++)	v[i]=rd(),s[i]=s[i-1]+v[i],l=max(l,v[i]),r+=v[i];
    	while(l<r)
    	{
    		mid=(l+r)>>1;
    		if(solve(mid))	r=mid;
    		else	l=mid+1;
    	}
    	printf("%d ",len=r);
    	for(i=1;i<=n;i++)
    	{
    		l=0,r=i;
    		while(l<r)
    		{
    			mid=(l+r)>>1;
    			if(s[i]-s[mid]<=len)	r=mid;
    			else	l=mid+1;
    		}
    		pre[i]=r;
    	}
    	f[0][0]=1;
    	for(i=0;i<=n;i++)	sf[0][i]=1;
    	for(i=1;i<=m;i++)
    	{
    		k=(i&1);
    		sf[k][0]=0;
    		for(j=1;j<=n;j++)
    		{
    			f[k][j]=(sf[k^1][j-1]-((!pre[j])?0:sf[k^1][pre[j]-1])+P)%P;
    			sf[k][j]=(sf[k][j-1]+f[k][j])%P;
    		}
    		ans=(ans+f[k][n])%P;
    	}
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    【t083】买票
    基于Linux应用层的6LOWPAN物联网网关及实现方法
    Express的路由详解
    day18 8.jdbc中设置事务隔离级别
    day18-事务与连接池 6.事务隔离级别与解决问题
    day36-hibernate检索和优化 02-Hibernate检索方式:简单查询及别名查询
    day37-hibernate 02-Hibernate二级缓存:二级缓存的散装数据
    day36-hibernate检索和优化 01-上次课内容回顾
    day36-hibernate检索和优化 05-Hibernate检索方式:离线条件查询
    SQL Server 涉及数据库安全常用SQL语句
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7468832.html
Copyright © 2011-2022 走看看