「Aに同じ数が含まれている」「Aの数が全てバラバラ」という2つの場合があるのですが、それぞれそうじゃない方だと解けない解法を使って解くというのが面白いなと。正解者数的に1100点の割にはかなり難しそう。
#include<bits/stdc++.h> using namespace std; #define pb push_back #define pf push_front typedef long long lint; typedef complex<double> P; #define mp make_pair #define fi first #define se second typedef pair<int,int> pint; #define All(s) s.begin(),s.end() #define rAll(s) s.rbegin(),s.rend() #define REP(i,a,b) for(int i=a;i<b;i++) #define rep(i,n) REP(i,0,n) lint dp[25010][420]; lint d3[25010][420][2]; int a[420]; lint zyo[25010],kai[420],ika[420]; lint mo=1000000007; map<int,int> me; lint extgcd(lint a, lint b, lint &x, lint &y) { lint g = a; x = 1; y = 0; if (b != 0) g = extgcd(b, a % b, y, x), y -= (a / b) * x; return g; } lint invMod(lint a, lint m) { lint x, y; if (extgcd(a, m, x, y) == 1) return (x + m) % m;return 0; } int cal(void) { int n,K,m,x=0,y=0;lint out=0; cin>>n>>K>>m; zyo[0]=1;rep(i,n+10) zyo[i+1]=(zyo[i]*K)%mo; kai[0]=1;rep(i,410) kai[i+1]=(kai[i]*(i+1))%mo; rep(i,410) ika[i]=invMod(kai[i],mo); rep(i,m) cin>>a[i]; rep(i,m-K+1){ int f=0;me.clear(); rep(j,K){ if(me[a[i+j]]>0) f=1;me[a[i+j]]++; } if(f<1){ return zyo[n-m]*(n-m+1)%mo; } } me.clear(); while(x<m){ if(me[a[x]]>0) break; me[a[x]]++;x++; } me.clear(); while(y<m){ if(me[a[m-1-y]]>0) break; me[a[m-1-y]]++;y++; } memset(dp,0,sizeof(dp)); memset(d3,0,sizeof(d3)); rep(i,n) REP(j,1,K){ dp[i+1][j]+=dp[i+1][j-1]; if(j==K-1) dp[i+1][j]+=zyo[i]; else dp[i+1][j]+=(dp[i][j+1]-dp[i][j])*(K-j); dp[i+1][j]%=mo; dp[i+1][j]+=dp[i][j]; dp[i+1][j]%=mo; } if(x>=m && y>=m){ d3[0][0][0]=1; rep(i,n+1) rep(j,K+1) rep(l,2){ if(j>0 && i>0){ d3[i][j][l]+=d3[i][j-1][l]; } d3[i][j][l]%=mo;d3[i][j][l]+=mo;d3[i][j][l]%=mo; d3[i+1][1][l]+=d3[i][j][l]; d3[i+1][j+1][l]+=mo-d3[i][j][l]; if(j<K-1){ d3[i+1][j+1][l]+=d3[i][j][l]*(K-j); d3[i+1][j+2][l]-=d3[i][j][l]*(K-j); } else if(j==K-1){ d3[i+1][j+1][1]+=d3[i][j][l]; d3[i+1][j+2][1]-=d3[i][j][l]; } } rep(i,n){ REP(j,m,K+1){ //既にできてるやつ out+=d3[i][j][1]*zyo[n-i]; out%=mo; //これから足すやつ。 out+=d3[i][j][0]*(dp[n-i][j]-dp[n-i][j-1]); out%=mo; } } REP(j,m,K+1){ out+=d3[n][j][1];out%=mo; } out*=kai[K-m];out%=mo;out*=ika[K];out%=mo;out+=mo;out%=mo; return out; } out=zyo[n-m]*(n-m+1)%mo; rep(i,n-m+1){ out-=(zyo[i]-dp[i][x]+dp[i][x-1])*(zyo[n-m-i]-dp[n-m-i][y]+dp[n-m-i][y-1]); out%=mo; } out+=mo;out%=mo; return out; } int main() { cout<<cal()<<endl; }
解説によるとO(N2^N)でできるらしいけどO(N^2 2^N)でも通った。こっちは逆に2300点という点数の割にはかなり簡単に思える。
#include<bits/stdc++.h> using namespace std; #define pb push_back #define pf push_front typedef long long lint; typedef complex<double> P; #define mp make_pair #define fi first #define se second typedef pair<int,int> pint; #define All(s) s.begin(),s.end() #define rAll(s) s.rbegin(),s.rend() #define REP(i,a,b) for(int i=a;i<b;i++) #define rep(i,n) REP(i,0,n) int dp[(1<<21)+10][22]; int main() { memset(dp,0,sizeof(dp)); int n,K;cin>>n>>K;string s; rep(i,n+1){ cin>>s; rep(j,(1<<i)){ if(s[j]=='1') dp[(1<<i)+j][i]++; } } for(int i=n;i>0;i--) rep(j,(1<<i)) rep(l,i+1){ if(dp[(1<<i)+j][l]<1) continue; rep(k,l){ if(k+1<i && ((j&(1<<k))>>k)==((j&(1<<(k+1)))>>(k+1))) continue; int to=(j>>(k+1)),bo=(j&((1<<k)-1)); dp[(1<<(i-1))+(to<<k)+bo][k]+=dp[(1<<i)+j][l]; } } for(int i=n;i>0;i--) rep(j,(1<<i)){ int sum=0; rep(k,i+1) sum+=dp[(1<<i)+j][k]; if(sum>=K){ string out=""; rep(l,i){ out+=('0'+(j%2));j/=2; } reverse(All(out)); cout<<out<<endl;return 0; } } cout<<""<<endl; }