1. 程式人生 > >D. Mysterious Crime

D. Mysterious Crime

連結

[http://codeforces.com/contest/1043/problem/D]

題意

給你一個m*n的矩陣(m<=10,n<=1e5),
每一行的數字是1到n裡不同的數字
問你這m行中有多少個公共子序列

分析

用一個二維陣列儲存每一行的每個位置的數字的前面一個數字是什麼,
然後後面用最後一行的數字和前面每一行對比,統計就好了,具體看程式碼就很容易理解了
還有一個組合數學的東西看下面圖片就好了

程式碼

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+10;
int a[N];
ll sum[N];
int pre[12][N];
int main(){
    int n,m,i,j;
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        memset(sum,0,sizeof(sum)); 
        for(i=1;i<=m;i++)
        for(j=1;j<=n;j++){
            scanf("%d",&a[j]);//因為重複使用a[],所以最後存的是最後一行的值 
          if(j>1) pre[i][a[j]]=a[j-1];//第存的是i行a[j]這個數字的前面一個數字 
        }
        ll ans=n;
        for(i=2;i<=n;i++){//只需要從第二個列的數字開始就可以了,因為第一個數字前面沒有數字 
         int cnt=0;
            for(j=1;j<m;j++)
                if(pre[j][a[i]]==pre[m][a[i]])
                cnt++;
            if(cnt==m-1) sum[i]+=sum[i-1]+1;//如果所有行都有公共的部分就可以加了
            //sum[i]+=sum[i-1]+1和組合數學有關,你可以想n個單位矩形挨在一起,
            //問你總共有多少個矩形是同一個問題就是個遞推 
            ans+=sum[i];
        }
        printf("%lld\n",ans); 
    }
    return 0;
}