动态规划训练之十
https://www.luogu.org/problem/P3120
首先ON^4的dp很容易想到(数据加强过,所以这个过不了)
code:
#include<bits/stdc++.h>
using namespace std;
int r,c,k; //行,列,数值限定
int a[751][751];
long long f[751][751]={0};
//f[i][j]:左上f[i][j]严格左上方所有点的路径总数之和
int main()
{
scanf("%d%d%d",&r,&c,&k);
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
scanf("%d",&a[i][j]);
f[0][0]=1;
for(int i=0;i<r;i++)
for(int j=0;j<c;j++) //要计算的点
for(int p=0;p<i;p++)
for(int q=0;q<j;q++) //左上方的点
if(a[i][j]!=a[p][q])//审题:要求数值不同
f[i][j]=(f[i][j]+f[p][q])%1000000007;
//勿忘mod 1000000007
cout<<f[r-1][c-1]<<endl;
return 0;
}
加强的数据完美卡到N^2*logN
首先如果没有两点的val值不同这个条件的话,直接维护二维前缀和就好
可是加了这个条件就很烦
还是考虑前缀和,两点的val值不同,那就先考虑两点val值相同的情况,
跟新答案时,用所有的前缀和减掉相同的情况就好
明显就只有权值线段树,
可是不同的val值可能有750*750个
不同的前缀和有750*750个
开不下啊,怎么办?,于是考虑动态开点
就愉(tong)快(ku)的AC了
code:
#include <bits/stdc++.h>
#define y1 y1_
#define index index_
#define pipe pipe_
#define next next_
#define endl '\n'
#define rgi register int
#define ll long long
#define Pi acos(-1.0)
#define lowbit(x) ((x&(-x)))
#define pb push_back
#define mk make_pair
#define pii pair<int,int>
#define fst first
#define scd second
using namespace std;
inline int read() {
int f=1,x=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=755;
const int MOD=1e9+7;
int n,m,K,a[MAXN][MAXN];
struct SegmentTree{
int ls,rs; ll sum;
}t[MAXN*MAXN*10];
int cnt;
void update(int l,int r,int &rt,int pos,int val) {
if(!rt) rt=++cnt;
if(l==r) {
t[rt].sum=(t[rt].sum+val)%MOD;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) update(l,mid,t[rt].ls,pos,val);
else update(mid+1,r,t[rt].rs,pos,val);
t[rt].sum=(t[t[rt].ls].sum+t[t[rt].rs].sum)%MOD;
}
ll sum[MAXN],dp[MAXN][MAXN];
ll query(int l,int r,int rt,int pos) {
if(!rt) return 0;
if(r<=pos) return t[rt].sum;
int mid=(l+r)>>1;
if(pos<=mid) return query(l,mid,t[rt].ls,pos);
else return (query(l,mid,t[rt].ls,pos)+query(mid+1,r,t[rt].rs,pos))%MOD;
}
int main() {
// freopen("","r",stdin);
// freopen("","w",stdout);
ios::sync_with_stdio(0);cin.tie(0);/*syn加速*/
n=read(); m=read(); K=read(); cnt=K;
for(rgi i=1;i<=n;++i) for(rgi j=1;j<=m;++j) a[i][j]=read();
for(rgi i=1;i<m;++i) sum[i]=1;
dp[1][1]=1; update(1,m,a[1][1],1,dp[1][1]);
for(rgi i=2;i<=n;++i) {
for(rgi j=2;j<=m;++j) {
dp[i][j]=(sum[j-1]-query(1,m,a[i][j],j-1)+MOD)%MOD;
}
ll tmp=0;
for(rgi j=2;j<=m;++j) {
tmp=(tmp+dp[i][j])%MOD;
sum[j]=(sum[j]+tmp)%MOD;
update(1,m,a[i][j],j,dp[i][j]);
}
}
cout<<dp[n][m]<<endl;
return 0;
}