洛谷 P3120 [USACO15FEB]牛跳房子(金)Cow Hopscotch (Gold)

P3120 【USACO15FEB】牛跳房子(金)Cow Hopscotch (Gold)

就像人类喜欢跳格子游戏一样,FJ的奶牛们发明了一种新的跳格子游戏。虽然这种接近一吨的笨拙的动物玩跳格子游戏几乎总是不愉快地结束,但是这并没有阻止奶牛们在每天下午参加跳格子游戏
游戏在一个R×C的网格上进行,每个格子有一个取值在1-k之间的整数标号,奶牛开始在左上角的格子,目的是通过若干次跳跃后到达右下角的格子,当且仅当格子A和格子B满足如下条件时能从格子A跳到格子B:
1.B格子在A格子的严格右方(B的列号严格大于A的列号)
2.B格子在A格子的严格下方(B的行号严格大于A的行号)
3.B格子的标号和A格子的标号不同
请你帮助奶牛计算出从左上角的格子到右下角的格子一共有多少种不同的方案
r,c<750,k<n*m

算法1:dp+离散化+树状数组

思路:

1.先将每种颜色所在的列统计起来,然后离散化

for(int i=1;i<=m;i++){
    for(int j=1;j<=n;j++){
        int color=a[j][i];
        if(!col[color].size()){
            col[color].push_back(0);
            bit[color].push_back(0);
        }
        if(col[color].back()!=i){
            col[color].push_back(i);
        }
    }
}
for(int i=1;i<=ccnt;i++){
    int siz=col[i].size();
    while(siz--){
        bit[i].push_back(0);
    }
    if(col[i].size()){
        bit[i].push_back(0);
    }
}
for(int i=0;i<=m;i++){
    tc.push_back(i);
    tot.push_back(0);
}
tot.push_back(0);

2.然后进行dp,用树状数组维护每种颜色每列的和

update(tot,getidx(tc,1),1);
update(bit[a[1][1]],getidx(col[a[1][1]],1),1);
for(int i=2;i<=n;i++){
    for(int j=m;j>=1;j--){
        int color=a[i][j];
        f[i][j]=query(tot,getidx(tc,j-1))-query(bit[color],getidx(col[color],j-1));//ºÏ²¢×ÓÎÊÌâ 
        if(f[i][j]<0){
            f[i][j]+=MOD;
        }
        update(bit[color],getidx(col[color],j),f[i][j]);
        update(tot,getidx(tc,j),f[i][j]);
    }
}

映射

inline int lowbit(int x){ return x&-x; }
inline int getidx(vector<int> clm,int idx){//Ó³Éä 
    int L=0,R=clm.size()-1,M,ret;
    while(L<=R){
        M=(L+R)/2;
        if(clm[M]<=idx){
            ret=M;
            L=M+1;
        }else{
            R=M-1;
        }
    }
    return ret+1;
}
inline void update(vector<int> &sum,int idx,int add){
    int siz=sum.size();
    while(idx<siz){
        sum[idx]=(sum[idx]+add)%MOD;
        idx+=lowbit(idx);
    }
}
inline int query(vector<int> &sum,int idx){
    int ret=0;
    while(idx){
        ret=(ret+sum[idx])%MOD;
        idx-=lowbit(idx);
    }
    return ret;
}

算法2:cdq优化,可以少一个log

#include<cstdio>
using namespace std;
const int MAXN=755,MAXC=562505,MOD=1e9+7;
int n,m,k,a[MAXN][MAXN];
int t[MAXC]/*×îºó³öÏÖµÄʱ¼ä£¬ÒÔÃâÖظ´ÇåÁãÀË·Ñʱ¼ä*/,timeclock;
long long f[MAXN][MAXN],s[MAXC];
void work(int l,int r){
    if(l>=r){
        return;
    }
    int mid=(l+r)/2,sum=0;
    work(l,mid);
    timeclock++;
    for(int j=1;j<=m;j++){//°´ÁÐÑ­»· 
        for(int i=r;i>=mid+1;i--){//ÏȽáËãÓÒÇø¼ä
            int color=a[i][j];
            if(t[color]!=timeclock){
                t[color]=timeclock;
                s[color]=0;
            }
            f[i][j]=(f[i][j]+sum-s[color]+MOD)%MOD;
        }
        for(int i=mid;i>=l;i--){
            int color=a[i][j];
            if(t[color]!=timeclock){
                t[color]=timeclock;
                s[color]=0;
            }
            s[color]=(s[color]+f[i][j])%MOD;
            sum=(sum+f[i][j])%MOD;
        }
    }
    work(mid+1,r);
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
        }
    }
    f[1][1]=1; 
    work(1,n);
    printf("%d",f[n][m]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/guoshaoyang/p/11120998.html