动态规划训练之十

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;
}
posted @ 2019-10-10 11:15  wzx_believer  阅读(93)  评论(0编辑  收藏  举报