只会爆搜系列
- 关于「本质不同的子序列个数」:限定长度,无限制(就是这题)
无限制的柿子是(令 \(dp[i]\) 为以 \(i\) 为结尾的不同子序列个数) \(dp[i] = \sum dp[j]+1\),代表在所有子序列末尾后面接上这个字母,且它自身也是一个子序列
然后这题还可以填上 \(m\) 个数,并要求最大化方案数
有个我没想到的贪心,每次填方案数最少的那个字母
因为根据上面的转移,无论这一次选哪个字母,它们的dp值都是一样的
于是发现我们填的数其实是 \(k\) 的一个排列
然后 \(m\) 很大而 \(k\) 只有 \(100\),考虑矩阵快速幂
每 \(k\) 次下来整体的转移是固定的,可以建出系数矩阵
剩下不足 \(k\) 的地方暴力处理就好了
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f
#define N 1000010
#define ll long long
#define ld long double
#define ull unsigned long long
#define fir first
#define sec second
#define make make_pair
#define reg register int
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, k; ll m;
int a[N];
const ll mod=1e9+7;
int mod2=1e9+7;
//inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
inline void md2(int& a, int b) {a+=b; a=a>=mod2?a-mod2:a;}
const ull base=131;
unordered_map<ull, bool> mp, mp2;
namespace task1{
void dfs(int u, ull dat) {
dat=dat*base+a[u];
mp[dat]=1;
for (int i=u+1; i<=n; ++i) {
dfs(i, dat);
}
}
void solve() {
for (int i=1; i<=n; ++i) dfs(i, 0);
cout<<mp.size()%mod<<endl;
exit(0);
}
}
namespace task2{
ull sta[N]; int top; unsigned ans;
void dfs(int u, unordered_map<ull, bool> tmp) {
//cout<<"dfs "<<u<<endl;
if (u>m) {ans=max(ans, tmp.size()); return ;}
top=0; ull tem;
for (int j=1; j<=k; ++j) {
//cout<<"j: "<<j<<endl;
unordered_map<ull, bool> tp2=tmp;
for (auto it:tmp) {
tem=it.fir;
tp2[tem*base+j]=1;
}
tp2[j]=1;
dfs(u+1, tp2);
}
}
void solve() {
for (int i=1; i<=n; ++i) task1::dfs(i, 0);
dfs(1, mp);
cout<<ans<<endl;
}
}
namespace task3{
ll dp[110]; ld dp2[110];
int sta[110], top;
void solve() {
ll sum; ld sum2;
for (int i=1; i<=n; ++i) {
sum=0; sum2=0;
for (int j=1; j<=k; ++j)
md(sum, dp[j]), sum2+=1.0*dp[j];
dp[a[i]]=sum, dp2[a[i]]=sum2+1.0;
md(dp[a[i]], 1);
}
for (int i=1,pos=0; i<=m; ++i,pos%=k) {
if (top==k) {
sum=0; sum2=0;
for (int j=1; j<=k; ++j)
md(sum, dp[j]), sum2+=dp[j];
dp[sta[pos]]=sum; dp2[sta[pos]]=sum2+1;
md(dp[sta[pos++]], 1);
}
else {
//ll minn=INF;
ld minn=1e1000l; int mini=0; sum=0; sum2=0;
for (int j=1; j<=k; ++j) {
if (dp2[j]<minn) minn=dp2[j], mini=j;
md(sum, dp[j]), sum2+=dp2[j];
}
dp[mini]=sum; dp2[mini]+=sum2;
md(dp[mini], 1);
sta[top++]=mini;
}
}
sum=0;
for (int i=1; i<=k; ++i) md(sum, dp[i]);
printf("%lld\n", sum);
exit(0);
}
}
namespace task{
int dp[110], sum3[110], vec[110];
queue<int> q;
struct matrix{
int a[110][110];
int n, m;
matrix() {memset(a, 0, sizeof(a));}
matrix(int x, int y):n(x),m(y) {memset(a, 0, sizeof(a));}
void resize(int a, int b) {n=a; m=b;}
void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}}
inline int* operator [] (int t) {return a[t];}
inline matrix operator * (matrix& b) {
matrix ans(n, b.m);
for (reg i=1; i<=n; ++i)
for (reg k=1; k<=m; ++k)
for (reg j=1; j<=b.m; ++j)
md2(ans[i][j], 1ll*a[i][k]*b[k][j]%mod);
return ans;
}
}mat, tem;
matrix qpow(matrix &a, ll b) {
matrix ans=a; --b;
while (b) {
if (b&1) ans=ans*a;
a=a*a; b>>=1;
}
return ans;
}
void solve() {
int sum=0, lst=0;
mat.resize(1, k+1); tem.resize(k+1, k+1);
int u;
for (reg i=1; i<=n; ++i) {
//cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
lst=dp[a[i]];
dp[a[i]]=sum;
md2(dp[a[i]], 1);
sum=(sum-lst+sum+1)%mod2;
sum=(sum+mod)%mod2;
vec[a[i]]=i;
}
//for (int i=1; i<=k; ++i) md(sum, dp[i]);
pair<int, int> s[110];
for (reg i=1; i<=k; ++i) s[i]=make(vec[i], i);
sort(s+1, s+k+1);
for (reg i=1; i<=k; ++i) q.push(s[i].sec);
int lim=m%k;
//cout<<"lim: "<<lim<<endl;
for (reg i=1,mini; i<=lim; ++i) {
u=q.front(); q.pop();
lst=dp[u];
dp[u]=sum;
md2(dp[u], 1);
sum=(sum-lst+sum+1)%mod2;
sum=(sum+mod2)%mod2;
q.push(u);
}
for (reg i=1; i<=k+1; ++i) tem[i][i]=1;
//cout<<"---tem(ini t)---"<<endl;
//tem.put(); cout<<endl;
for (reg i=1; i<=k; ++i) mat[1][i]=dp[i]; mat[1][k+1]=1;
for (reg i=1; i<=k; ++i) {
u=q.front(); q.pop();
memset(sum3, 0, sizeof(sum3));
for (reg j=1; j<=k; ++j)
for (reg h=1; h<=k+1; ++h)
md2(sum3[h], tem[j][h]);
memcpy(tem[u], sum3, sizeof(sum3));
++tem[u][k+1];
q.push(u);
}
for (reg i=1; i<=k+1; ++i)
for (reg j=i+1; j<=k+1; ++j)
swap(tem[i][j], tem[j][i]);
#if 0
cout<<"---mat---"<<endl;
mat.put(); cout<<endl;
cout<<"---tem---"<<endl;
tem.put(); cout<<endl;
cout<<"qpow: "<<m/k<<endl;
#endif
tem=qpow(tem, m/k);
mat=mat*tem;
ll ans=0;
//cout<<"---ans---"<<endl;
//for (int i=1; i<=k; ++i) cout<<mat[1][i]<<' '; cout<<endl;
for (reg i=1; i<=k; ++i) md(ans, mat[1][i]);
printf("%lld\n", ans);
exit(0);
}
}
signed main()
{
n=read(); m=read(); k=read();
for (int i=1; i<=n; ++i) a[i]=read();
if (!m) task3::solve();
else task::solve();
//task3::solve();
//task::solve();
return 0;
}