就是改成把一个字符串改成三进制状压,然后分成前5位,后5位统计,
然后直接统计 f[i][j][k]代表,后5局状压为k的,前5局比和j状态比输了5局的有多少个人
复杂度是O(T*30000*25*m)m比较小,也就最多几十吧,将将过
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cstdlib> #include <vector> #include <cmath> #include <queue> #include <map> #include <string> using namespace std; typedef long long LL; const int N=3e4+5; const int M=243; const int INF=0x3f3f3f3f; int get(int x,int y){ int ret=0; for(int k=0;k<5;++k){ int dig0=x%3,dig1=y%3; if(dig0==(dig1+1)%3)++ret; x/=3,y/=3; } return ret; } vector<int> win[6][M],lose[6][M]; int T,cas,n,a[N][11],ret[N][11],f[6][M][M]; char ch[15]; int main(){ for(int i=0;i<M;++i){ for(int j=0;j<M;++j){ win[get(i,j)][i].push_back(j); lose[get(i,j)][j].push_back(i); } } scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;++i) { scanf("%s",ch); for(int j=0;j<10;++j) { if(ch[j]=='R')a[i][j]=0; else if(ch[j]=='P')a[i][j]=1; else a[i][j]=2; } } memset(f,0,sizeof(f)); memset(ret,0,sizeof(ret)); for(int i=0;i<n;++i) { int mask0=0,mask1=0; for(int j=0;j<5;++j)mask0=mask0*3+a[i][j]; for(int j=5;j<10;++j)mask1=mask1*3+a[i][j]; for(int j=0;j<=5;++j) { for(int k=0;k<lose[j][mask0].size();++k) { int t=lose[j][mask0][k]; ++f[j][t][mask1]; } } } for(int i=0;i<n;++i){ int mask0=0,mask1=0; for(int j=0;j<5;++j)mask0=mask0*3+a[i][j]; for(int j=5;j<10;++j)mask1=mask1*3+a[i][j]; for(int s0=0;s0<=5;++s0) for(int s1=0;s1<=5;++s1){ for(int k=0;k<win[s1][mask1].size();++k){ int t=win[s1][mask1][k]; ret[i][s0+s1]+=f[s0][mask0][t]; } } --ret[i][0]; } printf("Case #%d: ",++cas); for(int i=0;i<n;++i){ for(int j=0;j<10;++j) printf("%d ",ret[i][j]); printf("%d ",ret[i][10]); } } return 0; }