【bzoj4584】[Apio2016]赛艇 dp
2016-05-12 15:22
260 查看
首先,对区间离散化,最终会最多形成2n-1个区间
f[i][j][k]表示考虑到第i个学校,最后一个数落在j区间中,第j个区间中有k个数的方案数
sum[t]=∑f[i-1][j][p] (1<=j<t)
f[i][j][k]=f[i-1][j][k]+f[i-1][j][k-1]*(len[j]-k+1)/k
f[i][j][1]=f[i-1][j][1]+sum[j-1]*len[j]
前缀和优化一下就好了,考试的时候没有想清楚落在同一个区间中如何处理,所以导致最终思路偏了
可以优化空间,倒序枚举k即可
我该如何骂我自己好呢?
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 510
#define mod 1000000007
using namespace std;
struct yts
{
int l,r;
}q[maxn],seq[2*maxn];
int a[2*maxn];
int inv[1010];
int f[2*maxn][maxn],len[2*maxn];
int sum[2*maxn];
int dp[maxn][2*maxn];
int n,m,tot,num;
int query_l(int x)
{
int l=1,r=num,ans;
while (l<=r)
{
int mid=(l+r)/2;
if (x<=seq[mid].l) ans=mid,r=mid-1; else l=mid+1;
}
return ans;
}
int query_r(int x)
{
int l=1,r=num,ans;
while (l<=r)
{
int mid=(l+r)/2;
if (seq[mid].r<x) ans=mid,l=mid+1; else r=mid-1;
}
return ans;
}
int power(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(long long)ans*x%mod;
x=(long long)x*x%mod;
y>>=1;
}
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
y++;
q[i].l=x;q[i].r=y;
a[++tot]=x;a[++tot]=y;
}
for (int i=1;i<=1000;i++) inv[i]=power(i,mod-2);
sort(a+1,a+tot+1);
for (int i=1;i<tot;i++)
if (a[i]!=a[i+1]) seq[++num].l=a[i],seq[num].r=a[i+1]-1,len[num]=a[i+1]-a[i];
for (int i=1;i<=n;i++) q[i].l=query_l(q[i].l),q[i].r=query_r(q[i].r);
for (int i=0;i<=num;i++) sum[i]=1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=num;j++) dp[i][j]=dp[i-1][j];
for (int j=q[i].l;j<=q[i].r;j++) dp[i][j]++;
}
for (int i=1;i<=n;i++)
{
for (int j=q[i].l;j<=q[i].r;j++)
{
for (int k=dp[i][j];k>=2;k--)
f[j][k]=(f[j][k]+((long long)f[j][k-1]*(len[j]-k+1)%mod)*inv[k]%mod)%mod;
f[j][1]=(f[j][1]+(long long)sum[j-1]*len[j]%mod)%mod;
}
sum[0]=1;
for (int j=1;j<=num;j++)
{
sum[j]=sum[j-1];
for (int k=1;k<=dp[i][j];k++) sum[j]=(sum[j]+f[j][k])%mod;
}
}
int ans=0;
for (int i=1;i<=num;i++)
for (int j=1;j<=n;j++)
ans=(ans+f[i][j])%mod;
printf("%d\n",ans);
return 0;
}
f[i][j][k]表示考虑到第i个学校,最后一个数落在j区间中,第j个区间中有k个数的方案数
sum[t]=∑f[i-1][j][p] (1<=j<t)
f[i][j][k]=f[i-1][j][k]+f[i-1][j][k-1]*(len[j]-k+1)/k
f[i][j][1]=f[i-1][j][1]+sum[j-1]*len[j]
前缀和优化一下就好了,考试的时候没有想清楚落在同一个区间中如何处理,所以导致最终思路偏了
可以优化空间,倒序枚举k即可
我该如何骂我自己好呢?
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 510
#define mod 1000000007
using namespace std;
struct yts
{
int l,r;
}q[maxn],seq[2*maxn];
int a[2*maxn];
int inv[1010];
int f[2*maxn][maxn],len[2*maxn];
int sum[2*maxn];
int dp[maxn][2*maxn];
int n,m,tot,num;
int query_l(int x)
{
int l=1,r=num,ans;
while (l<=r)
{
int mid=(l+r)/2;
if (x<=seq[mid].l) ans=mid,r=mid-1; else l=mid+1;
}
return ans;
}
int query_r(int x)
{
int l=1,r=num,ans;
while (l<=r)
{
int mid=(l+r)/2;
if (seq[mid].r<x) ans=mid,l=mid+1; else r=mid-1;
}
return ans;
}
int power(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(long long)ans*x%mod;
x=(long long)x*x%mod;
y>>=1;
}
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
y++;
q[i].l=x;q[i].r=y;
a[++tot]=x;a[++tot]=y;
}
for (int i=1;i<=1000;i++) inv[i]=power(i,mod-2);
sort(a+1,a+tot+1);
for (int i=1;i<tot;i++)
if (a[i]!=a[i+1]) seq[++num].l=a[i],seq[num].r=a[i+1]-1,len[num]=a[i+1]-a[i];
for (int i=1;i<=n;i++) q[i].l=query_l(q[i].l),q[i].r=query_r(q[i].r);
for (int i=0;i<=num;i++) sum[i]=1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=num;j++) dp[i][j]=dp[i-1][j];
for (int j=q[i].l;j<=q[i].r;j++) dp[i][j]++;
}
for (int i=1;i<=n;i++)
{
for (int j=q[i].l;j<=q[i].r;j++)
{
for (int k=dp[i][j];k>=2;k--)
f[j][k]=(f[j][k]+((long long)f[j][k-1]*(len[j]-k+1)%mod)*inv[k]%mod)%mod;
f[j][1]=(f[j][1]+(long long)sum[j-1]*len[j]%mod)%mod;
}
sum[0]=1;
for (int j=1;j<=num;j++)
{
sum[j]=sum[j-1];
for (int k=1;k<=dp[i][j];k++) sum[j]=(sum[j]+f[j][k])%mod;
}
}
int ans=0;
for (int i=1;i<=num;i++)
for (int j=1;j<=n;j++)
ans=(ans+f[i][j])%mod;
printf("%d\n",ans);
return 0;
}
相关文章推荐
- 使用spool输出csv格式查看系统表空间使用情况
- 详解Scala的Option的模式匹配
- JAVA反射
- Android RecyclerView使用Demo
- 最大似然估计和最大后验估计
- SDK开发
- MacOsx自动安装工具:brew
- 动物产生式识别系统
- Markdown 语法和 MWeb 写作使用说明(个人留存)
- 画图
- freemarker利用word模版导出word文档
- 关系型数据库之Mysql查询及数据库管理(二)
- hdu 5676ztr loves lucky numbers(全排列函数)
- oracle中length、lengthb、substr、substrb用法小结
- Prefix.pch文件的添加方式
- Android判断包名和类名是否存在的方法
- android 自定义 PDF view
- 八数码问题
- 责任链模式
- 剑指offer之面试题40数组中只出现一次的数字