[矩乘优化DP] Topcoder SRM550 DIV1 Hard. ConversionMachine

24 篇文章 0 订阅
7 篇文章 0 订阅

每个位置显然是先变成正确的,然后进去若干循环

这样就可以算出最多进行多少轮变换,

fi,j,k 表示进行了 i 轮变换,有 j 个位置差一次变换, k <script type="math/tex" id="MathJax-Element-66">k</script> 个位置差两次变换

直接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>  

using namespace std;  

typedef long long ll;

const int N=256,P=1e9+7;

int n,m,S;
int c[3][3];

int u[N][N],f[N][N];

inline void mul(int a[][N],int b[][N],int c[][N]){
  static int tmp[N][N];
  memset(tmp,0,sizeof(tmp));
  for(int i=1;i<=S;i++)
    for(int j=1;j<=S;j++)
      for(int k=1;k<=S;k++)
    tmp[i][j]=(tmp[i][j]+1LL*a[i][k]*b[k][j])%P;
  memcpy(c,tmp,sizeof(tmp));
}

inline void Pow(int a[][N],int y,int b[][N]){
  static int tmp1[N][N];
  memset(tmp1,0,sizeof(tmp1));
  for(int i=1;i<=S;i++) tmp1[i][i]=1;
  for(;y;y>>=1,mul(a,a,a)) if(y&1) mul(a,tmp1,tmp1);
  memcpy(b,tmp1,sizeof(tmp1));
}

inline int g(int x,int y){
  return x*(n+1)+y+1;
}

inline int dis(char a,char b){
  if(a==b) return 0;
  if(a=='a' && b=='b') return 1;
  if(a=='b' && b=='c') return 1;
  if(a=='c' && b=='a') return 1;
  return 2;
}

class ConversionMachine{  
public:  
  int countAll(string word1, string word2, vector <int> costs, int maxCost){
    memset(u,0,sizeof(u)); memset(f,0,sizeof(f)); 
    n=word1.size(); ll cur=0,cc=costs[0]+costs[1]+costs[2];
    c[0][1]=costs[0]; c[1][2]=costs[1]; c[2][0]=costs[2];
    c[0][2]=c[0][1]+c[1][2]; c[1][0]=c[1][2]+c[2][0]; c[2][1]=c[2][0]+c[0][1];
    for(int i=0;i<n;i++) cur+=c[word1[i]-'a'][word2[i]-'a'];
    if(cur>maxCost) return 0;
    m=(maxCost-cur)/cc*3; S=(n+1)*(n+1); S++;
    for(int j=0;j<=n;j++)
      for(int k=0;k<=n;k++){
    if(j<n) u[g(j,k)][g(j+1,k)]=j+1;
    if(k) u[g(j,k)][g(j,k-1)]=n-j-k+1;
    if(j && k<n) u[g(j,k)][g(j-1,k+1)]=k+1;
      }
    u[S][g(0,0)]=1;
    u[S][S]=1;
    int cj=0,ck=0;
    for(int i=0;i<n;i++){
      if(dis(word1[i],word2[i])==1) cj++;
      if(dis(word1[i],word2[i])==2) ck++;
    }

    m+=cj+2*ck;
    f[g(cj,ck)][1]=1;
    Pow(u,m,u);
    mul(u,f,f);
    return (f[S][1]+f[g(0,0)][1])%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(); }
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() { string Arg0 = "a"; string Arg1 = "b"; int Arr2[] = {100,2,3}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 205; int Arg4 = 2; verify_case(0, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); }
  void test_case_1() { string Arg0 = "abcba"; string Arg1 = "abcba"; int Arr2[] = {67,23,43}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 0; int Arg4 = 1; verify_case(1, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); }
  void test_case_2() { string Arg0 = "cccccccc"; string Arg1 = "aaaaaaaa"; int Arr2[] = {10000000,1,1}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 100; int Arg4 = 40320; verify_case(2, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); }
  void test_case_3() { string Arg0 = "aa"; string Arg1 = "cc"; int Arr2[] = {1,10,100}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 1787; int Arg4 = 123611681; verify_case(3, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); }

  // END CUT HERE

};  

// BEGIN CUT HERE  
int main()  
{  
  ConversionMachine ___test;  
  ___test.run_test(-1);  
  system("pause");  
}  
// END CUT HERE  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值