[补集转换 DP] Topcoder SRM 509 DIV1 Hard. NumberLabyrinthDiv1

fi,j,k 表示第 i 个点通过加了 k 个点到 j 的方案数
gi,j,k 表示第 i 个点通过加了 k 个点到 j 且不经过其他点的方案数

gi,j,k 可以通过补集转换计算出
然后DP就很简单了

// BEGIN CUT HERE  

// END CUT HERE  
#include <vector>  
#include <list>  
#include <map>  
#include <set>  
#include <deque>  
#include <stack>  
#include <bitset>  
#include <algorithm>  
#include <functional>  
#include <numeric>  
#include <utility>  
#include <sstream>  
#include <iostream>  
#include <iomanip>  
#include <cstdio>  
#include <cmath>  
#include <cstdlib>  
#include <ctime>  
#include <queue>
#include <assert.h>
#include <cstring>  
#define pb push_back
#define fi first
#define se second

using namespace std;  

const int N=510,P=1e9+9,NN=1000010;

int n,x,y;
int f[N][N][20],g[N][N][20],h[N][20];
int fac[NN],inv[NN];

struct Ps{
  int x,y,v,f;
  friend bool operator <(Ps a,Ps b){
    return a.x<b.x || (a.x==b.x && a.y<b.y);
  }
}a[N];

inline int C(int x,int y){
  if(x<0 || y<0 || x<y) return 0;
  return 1LL*fac[x]*inv[y]%P*inv[x-y]%P;
}

inline int calc(int x,int y,int tx,int ty,int k){
  if(x>tx || y>ty) return 0;
  if(x==tx && y==ty) return !k;
  if(x==tx) return C(ty-y-1,k-1);
  if(y==ty) return C(tx-x-1,k-1);
  int ret=0;
  for(int s=1;s<k;s++)
    ret=(ret+1LL*C(k,s)*C(tx-x-1,s-1)%P*C(ty-y-1,k-s-1))%P;
  return ret;
}

class NumberLabyrinthDiv1{  
public:  
  int getNumberOfPaths(vector <int> X, vector <int> Y, vector <int> val, int xFinish, int yFinish, int K) {
    x=xFinish; y=yFinish; n=0;
    memset(h,0,sizeof(h));
    memset(g,0,sizeof(g));
    memset(f,0,sizeof(f));
    for(int i=0;i<X.size();i++){
      a[++n].x=X[i]; a[n].y=Y[i]; a[n].v=val[i];
    }
    a[++n].x=0; a[n].y=0; a[n].v=0; a[++n].x=x; a[n].y=y; a[n].v=0;
    sort(a+1,a+1+n);
    fac[0]=1; for(int i=1;i<=1000000;i++) fac[i]=1LL*fac[i-1]*i%P;
    inv[1]=1; for(int i=2;i<=1000000;i++) inv[i]=1LL*(P-P/i)*inv[P%i]%P;
    inv[0]=1; for(int i=1;i<=1000000;i++) inv[i]=1LL*inv[i]*inv[i-1]%P;
    for(int i=2;i<=n;i++)
      for(int j=1;j<i;j++){
    for(int k=0;k<=K;k++){
      f[j][i][k]=calc(a[j].x+a[j].v,a[j].y,a[i].x,a[i].y,k);
      if(a[j].v) f[j][i][k]=(f[j][i][k]+calc(a[j].x,a[j].y+a[j].v,a[i].x,a[i].y,k))%P;
    }
      }
    for(int i=2;i<=n;i++)
      for(int j=i-1;j;j--)
    for(int k=0;k<=K;k++){
      g[j][i][k]=f[j][i][k];
      for(int s=j+1;s<i;s++){
        for(int _k=0;_k<=k;_k++)
          g[j][i][k]=(g[j][i][k]-1LL*g[j][s][_k]*calc(a[s].x,a[s].y,a[i].x,a[i].y,k-_k))%P;
      }
      }
    for(int i=1;i<=n;i++)
      for(int j=0;j<=K;j++) h[i][j]=g[1][i][j];
    for(int i=2;i<=n;i++)
      for(int j=1;j<i;j++)
    for(int k=0;k<=K;k++)
      for(int s=0;s<=k;s++)
        h[i][k]=(h[i][k]+1LL*h[j][s]*g[j][i][k-s])%P;
    int p,ans=0;
    for(int i=1;i<=n;i++)
      if(a[i].x==x && a[i].y==y){
    p=i; break;
      }
    for(int i=0;i<=K;i++) ans=(ans+h[p][i])%P;
    return (ans+P)%P;
  }


// BEGIN CUT HERE
    public:
    void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); if ((Case == -1) || (Case == 5)) test_case_5(); }
    private:
    template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
    void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
    void test_case_0() { int Arr0[] = {}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 3; int Arg4 = 3; int Arg5 = 2; int Arg6 = 2; verify_case(0, Arg6, getNumberOfPaths(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
    void test_case_1() { int Arr0[] = {}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 3; int Arg4 = 3; int Arg5 = 3; int Arg6 = 14; verify_case(1, Arg6, getNumberOfPaths(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
    void test_case_2() { int Arr0[] = {2}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {2}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 3; int Arg4 = 3; int Arg5 = 3; int Arg6 = 18; verify_case(2, Arg6, getNumberOfPaths(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
    void test_case_3() { int Arr0[] = {1, 3, 6}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {1, 3, 6}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {2, 2, 2}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 5; int Arg4 = 5; int Arg5 = 4; int Arg6 = 210; verify_case(3, Arg6, getNumberOfPaths(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
    void test_case_4() { int Arr0[] = {1, 19, 20, 21, 21, 21, 20, 19, 19}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {1, 11, 11, 11, 10, 9, 9, 9, 10}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1, 2, 2, 2, 2, 2, 2, 2, 2}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 20; int Arg4 = 10; int Arg5 = 4; int Arg6 = 1778; verify_case(4, Arg6, getNumberOfPaths(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
    void test_case_5() { int Arr0[] = {13, 224, 77, 509, 1451, 43, 379, 142, 477}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {1974, 375, 38, 783, 3, 1974, 1790, 1008, 2710}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {30, 1845, 360, 11, 837, 84, 210, 4, 6704}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 509; int Arg4 = 2011; int Arg5 = 10; int Arg6 = 196052726; verify_case(5, Arg6, getNumberOfPaths(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }

// END CUT HERE

};  

// BEGIN CUT HERE  
int main()  
{  
  NumberLabyrinthDiv1 ___test;  
  ___test.run_test(5);  
  system("pause");  
}  
// END CUT HERE  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值