E99 线性DP+前缀和优化 P3643 [APIO2016] 划艇

视频链接:E99 线性DP+前缀和优化 P3643 [APIO2016] 划艇_哔哩哔哩_bilibili

 

 

 

 

参考:G13 同余式 乘法逆元 费马小定理 - 董晓 - 博客园

P3643 [APIO2016] 划艇 - 洛谷

复制代码
// 线性DP+前缀和优化 O(n^3)
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=505,M=1e9+7;
int n,m,ans;
int a[N],b[N],x[N<<1],inv[N],C[N],f[N],g[N];

int qpow(int a,int b){
  int s=1;
  while(b){
    if(b&1) s=s*a%M;
    a=a*a%M;
    b>>=1;
  }
  return s;
}
signed main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    scanf("%d%d",&a[i],&b[i]);
    x[i]=a[i]; //左闭
    x[i+n]=++b[i]; //右开
  }
  sort(x+1,x+1+2*n);
  m=unique(x+1,x+1+2*n)-x-1;
  for(int i=1;i<=n;i++){
    a[i]=lower_bound(x+1,x+1+m,a[i])-x;
    b[i]=lower_bound(x+1,x+1+m,b[i])-x;
  }
  
  f[0]=g[0]=C[0]=inv[1]=1;
  for(int i=2;i<=n;i++) inv[i]=qpow(i,M-2);
  
  for(int j=1;j<m;j++){ //第j区间
    int L=x[j+1]-x[j];
    for(int i=1;i<=n;i++)
      C[i]=C[i-1]*(L+i-1)%M*inv[i]%M;
    for(int i=n;i;i--){ //前i学校
      if(a[i]<=j&&b[i]>=j+1){
        for(int s=1,k=i-1;k>=0;k--){
          f[i]=(f[i]+g[k]*C[s])%M;
          if(a[k]<=j&&b[k]>=j+1) s++;
        }
      }
      g[i]=f[i]; //前缀和
    }
  }
  for(int i=1;i<=n;i++) ans=(ans+f[i])%M;
  printf("%d\n",ans);
}
复制代码

 

复制代码
// 线性DP+前缀和优化 O(n^3)
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=505,M=1e9+7;
int n,m,ans;
int a[N],b[N],x[N<<1],inv[N],C[N],f[N];

int qpow(int a,int b){
  int s=1;
  while(b){
    if(b&1) s=s*a%M;
    a=a*a%M;
    b>>=1;
  }
  return s;
}
signed main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    scanf("%d%d",&a[i],&b[i]);
    x[i]=a[i]; //左闭
    x[i+n]=++b[i]; //右开
  }
  sort(x+1,x+1+2*n);
  m=unique(x+1,x+1+2*n)-x-1;
  for(int i=1;i<=n;i++){
    a[i]=lower_bound(x+1,x+1+m,a[i])-x;
    b[i]=lower_bound(x+1,x+1+m,b[i])-x;
  }
  
  f[0]=C[0]=inv[1]=1;
  for(int i=2;i<=n;i++) inv[i]=qpow(i,M-2);
  
  for(int j=1;j<m;j++){ //第j区间
    int L=x[j+1]-x[j];
    for(int i=1;i<=n;i++)
      C[i]=C[i-1]*(L+i-1)%M*inv[i]%M;
    for(int i=n;i;i--){ //前i学校
      if(a[i]<=j&&b[i]>=j+1){
        for(int s=1,k=i-1;k>=0;k--){
          f[i]=(f[i]+f[k]*C[s])%M;
          if(a[k]<=j&&b[k]>=j+1) s++;
        }
      }
    }
  }
  for(int i=1;i<=n;i++) ans=(ans+f[i])%M;
  printf("%d\n",ans);
}
复制代码

 

递推逆元:乘法逆元 - zjp_shadow - 博客园

复制代码
// 线性DP+前缀和优化 O(n^3)
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=505,M=1e9+7;
int n,m,ans;
int a[N],b[N],x[N<<1],inv[N],C[N],f[N];

signed main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    scanf("%d%d",&a[i],&b[i]);
    x[i]=a[i]; //左闭
    x[i+n]=++b[i]; //右开
  }
  sort(x+1,x+1+2*n);
  m=unique(x+1,x+1+2*n)-x-1;
  for(int i=1;i<=n;i++){
    a[i]=lower_bound(x+1,x+1+m,a[i])-x;
    b[i]=lower_bound(x+1,x+1+m,b[i])-x;
  }
  
  f[0]=C[0]=inv[1]=1;
  for(int i=2;i<=n;i++) inv[i]=(M-M/i)*inv[M%i]%M;
  
  for(int j=1;j<m;j++){ //第j区间
    int L=x[j+1]-x[j];
    for(int i=1;i<=n;i++)
      C[i]=C[i-1]*(L+i-1)%M*inv[i]%M;
    for(int i=n;i;i--){ //前i学校
      if(a[i]<=j&&b[i]>=j+1){
        for(int s=1,k=i-1;k>=0;k--){
          f[i]=(f[i]+f[k]*C[s])%M;
          if(a[k]<=j&&b[k]>=j+1) s++;
        }
      }
    }
  }
  for(int i=1;i<=n;i++) ans=(ans+f[i])%M;
  printf("%d\n",ans);
}
复制代码

 

复制代码
// 线性DP+前缀和优化 O(n^3) 滚动数组&正序枚举
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=505,M=1e9+7;
int n,m,ans;
int a[N],b[N],x[N<<1],inv[N],C[N],f[N],g[2][N];

int qpow(int a,int b){
  int s=1;
  while(b){
    if(b&1) s=s*a%M;
    a=a*a%M;
    b>>=1;
  }
  return s;
}
signed main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    scanf("%d%d",&a[i],&b[i]);
    x[i]=a[i]; //左闭
    x[i+n]=++b[i]; //右开
  }
  sort(x+1,x+1+2*n);
  m=unique(x+1,x+1+2*n)-x-1;
  for(int i=1;i<=n;i++){
    a[i]=lower_bound(x+1,x+1+m,a[i])-x;
    b[i]=lower_bound(x+1,x+1+m,b[i])-x;
  }
  
  f[0]=g[0][0]=g[1][0]=C[0]=inv[1]=1;
  for(int i=2;i<=n;i++) inv[i]=qpow(i,M-2);
  
  for(int j=1;j<m;j++){ //第j区间
    int L=x[j+1]-x[j];
    for(int i=1;i<=n;i++)
      C[i]=C[i-1]*(L+i-1)%M*inv[i]%M;
      
    int s=0,t;  
    for(int i=1;i<=n;i++){ //前i学校
      if(a[i]<=j&&b[i]>=j+1){
        t=++s;
        for(int k=0;k<=i-1;k++){
          if(a[k]<=j&&b[k]>=j+1) t--; 
          f[i]=(f[i]+g[j&1][k]*C[t])%M;
        }
      }
      g[j+1&1][i]=f[i]; //前缀和
    }
  }
  for(int i=1;i<=n;i++) ans=(ans+f[i])%M;
  printf("%d\n",ans);
}
复制代码

 

posted @   董晓  阅读(99)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示