需要滚动优化或者short int卡空间

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,10
00),1<=Li<=1000.

Output

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

Sample Input

3 2
1
1
10

Sample Output

10 2

HINT

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


题目分析

昨天做到这道题的稍微强化版:允许空集存在。我那题想法是,强制没有空集,最后再用组合数统计答案。状态$f[i][j]$表示前$i$个数分为$j$个非空集合的方案数,$t[i]$表示最小能够与$i$合并的位置。于是$f[i][j]=\sum_{x=t[i]}^{i}{f[i][j-1]}$。这里有一个$\sum_{i}{f[i][j]}$的形式,自然用前缀和优化。

组合数溢出调了好久……

 #include<bits/stdc++.h>
const int maxn = ;
const int MO = ; int n,m,mxBound,mnBound,ans;
int a[maxn],s[maxn],t[maxn],g[maxn][maxn];
int f[maxn][maxn];
int C[maxn][maxn]; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
bool check(int x)
{
int cnt = , sum = ;
for (int i=; i<=n; i++)
if (sum+a[i] > x) sum = a[i], cnt++;
else sum += a[i];
return cnt <= m;
}
int qmi(int a, int b)
{
int ret = ;
while (b)
{
if (b&) ret = 1ll*ret*a%MO;
a = 1ll*a*a%MO, b >>= ;
}
return ret;
}
int main()
{
// freopen("ex_t2.in","r",stdin);
n = read(), m = read(), C[][] = ;
for (int i=; i<=m; i++)
{
C[i][] = ;
for (int j=; j<=i; j++)
C[i][j] = (C[i-][j]+C[i-][j-])%MO;
}
for (int i=; i<=n; i++)
a[i] = read(), mxBound += a[i], mnBound = mnBound < a[i]?a[i]:mnBound, s[i] = s[i-]+a[i];
int l = mnBound, r = mxBound, head = , tot = ;
for (int mid=(l+r)>>; l<=r; mid=(l+r)>>)
if (check(mid)) ans = mid, r = mid-;
else l = mid+;
printf("%d\n",ans);
for (int i=; i<=n; i++)
{
tot += a[i];
while (tot > ans) tot -= a[head++];
t[i] = head;
}
g[][] = f[][] = , ans = ;
for (int i=; i<=n; i++)
{
g[i][] = ;
for (int j=; j<=m; j++)
{
int delta = g[i-][j-];
if (t[i]>) delta -= g[t[i]-][j-];
(f[i][j] += 1ll*delta+MO) %= MO;
(g[i][j] = 1ll*g[i-][j]+1ll*f[i][j]) %= MO;
}
}
for (int i=; i<=m; i++)
ans = (ans+1ll*C[m][i]*f[n][i])%MO;
printf("%d\n",ans);
return ;
}

但是强化版空间512M,这题却只有162M。

首当其冲想到滚动数组优化,不过由于在这题里滚动数组需要把$j$放在枚举的外层,因此在一些奇怪的原因影响下效率会变得非常低。

注意到本题的模数非常小(不知道是不是出题人的善意),于是可以把$f[i][j]$开成short int省去一半空间。

再注意到其实同时开$f[i][j]$与$g[i][j]$是没有必要的,我们完全可以把$f[i][j]$表示成$g[i][j]$的前缀和形式,从而又省去一半空间。

 #include<bits/stdc++.h>
const int maxn = ;
const int maxm = ;
const int MO = ; int n,m,mxBound,mnBound,ans;
int a[maxn],s[maxn],t[maxn];
short int g[maxn][maxm]; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
bool check(int x)
{
int cnt = , sum = ;
for (int i=; i<=n; i++)
if (sum+a[i] > x) sum = a[i], cnt++;
else sum += a[i];
return cnt <= m;
}
int main()
{
// freopen("1044.in","r",stdin);
// freopen("1044.out","w",stdout);
n = read(), m = read()+;
for (int i=; i<=n; i++)
a[i] = read(), mxBound += a[i], mnBound = mnBound < a[i]?a[i]:mnBound, s[i] = s[i-]+a[i];
int l = mnBound, r = mxBound, head = , tot = ;
for (int mid=(l+r)>>; l<=r; mid=(l+r)>>)
if (check(mid)) ans = mid, r = mid-;
else l = mid+;
printf("%d ",ans);
for (int i=; i<=n; i++)
{
tot += a[i];
while (tot > ans) tot -= a[head++];
t[i] = head;
}
register int i,j;
ans = ;
for (i=; i<=n; i++) g[i][] = ;
for (int i=; i<=n; i++)
{
for (int j=; j<=m; j++)
{
int delta = g[i-][j-];
if (t[i]>) delta -= g[t[i]-][j-];
(g[i][j] = g[i-][j]+delta) %= MO;
}
}
for (i=; i<=m; i++)
ans = (ans+g[n][i]-g[n-][i]+MO)%MO;
printf("%d\n",ans);
return ;
}

END

最新文章

  1. 【记录】WCF IIS 404
  2. 【面试必备】CSS盒模型的点点滴滴
  3. 关于CPU Cache -- 程序猿需要知道的那些事
  4. 如何在Windows 下安装Python
  5. ElasticSearch 的 聚合(Aggregations)
  6. 练习—单链表—Swap Nodes in Pairs
  7. Android编译过程详解(二)
  8. Bash shell 简单的并行任务,并等待
  9. MyEclipse安装SVN插件
  10. Mybatis异常--There is no getter for property named &#39;XXX&#39; in &#39;class java.lang.String&#39;
  11. python中的魔法属性
  12. BeanPostProcessor出现init方法无法被调用Invocation of init method failed
  13. MyBatis基础入门《九》ResultMap自动匹配
  14. AnswerOpenCV(0826-0901)一周佳作欣赏
  15. Echarts 设置地图大小
  16. 12.输入一个成绩计算其A,B,C,D,E等级
  17. java面试题001
  18. 【Android实验】 数据存储与访问sqlite
  19. JAVA Spring JavaBean 属性值的注入方式( 属性注入, 特殊字符注入 &lt;![CDATA[ 带有特殊字符的值 ]]&gt; , 构造器注入 )
  20. hadoop学习笔记(一):概念和组成

热门文章

  1. 【Linux】Devops的一些运维工具
  2. 简单重载运算符in priority_queue By cellur925
  3. eclipse svn 相关
  4. react-native-wechat微信组件的使用
  5. iPhone X的适配问题
  6. Zynq7000开发系列-7(在Zybo上运行Linaro桌面系统)
  7. 抛出异常-throws和throw
  8. 缺少mscvr100.dll
  9. Codeforces 1142B(倍增)
  10. 命令行视频下载工具 you-get 和 youtube-dl