C Two Arrays(线性DP,前缀和)

传送门
题目思路很好想,用dp[i][j][k]表示第i个数,a[i]放j,b[i]放k的方案数.
暴力转移的话复杂度是O(m×n4),用前缀和可以优化到O(m×n2).
dp[i][j][k] = sum{dp[i-1][1->j][k->n]}
代码

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;
const int mod = 1e9+7;

inline void read(int &a){
    
    
    int x = 0,f=1;char ch = getchar();
    while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
    a = x*f;
}
LL dp[11][1010][1010],sum[1010];
int main(){
    
    
    int n,m;
    cin >> n >> m;
    LL ans = 0;
    fir(i,1,n){
    
    
        fir(j,i,n){
    
    
            dp[1][i][j] = 1;
            if(m == 1) ans = ( dp[1][i][j] + ans ) % mod;
        }
    }
    fir(i,2,m){
    
    
        mem(sum,0);
        fir(j,1,n){
    
    
            LL tmp = 0;
            afir(k,n,j){
    
    
                tmp = (tmp + dp[i-1][j][k])%mod;
                sum[k] = (sum[k+1] + tmp)%mod;
                dp[i][j][k] = sum[k];
                if(i == m) ans = (ans+dp[i][j][k])%mod;
            }
        }
    }
    cout << ans << endl;
    
    return 0;
}    

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/109144271