题解 茅山道术
先把相邻的同色的点缩点
每个点向上一个同色的点连边
发现就是求选出几条边,使它们不相交的方案数
考虑令 \(dp[i][j]\) 为考虑到位置 \(i\),上一次选点为 \(j\) 时的方案数
可以树状数组优化转移
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#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 int read() {
int 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;
int c[N];
const ll mod=1e9+7;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
namespace task1{
int pre[N], lst[N], bkp[N], tot;
ll dp[2010][2010];
void solve() {
dp[0][0]=1;
memset(lst, -1, sizeof(lst));
memcpy(bkp, c, sizeof(c));
for (int pos2=1; pos2<=n; ++pos2)
if (bkp[pos2-1]!=bkp[pos2]) c[++tot]=bkp[pos2];
for (int i=1; i<=tot; ++i) {
pre[i]=lst[c[i]];
lst[c[i]]=i;
}
//cout<<"pre: "; for (int i=1; i<=tot; ++i) cout<<pre[i]<<' '; cout<<endl;
for (int i=1; i<=tot; ++i) {
for (int j=0; j<i; ++j) {
dp[i][j] = dp[i-1][j];
if (pre[i]>=j) dp[i][i]=(dp[i][i]+dp[i-1][j])%mod;
}
}
ll ans=0;
for (int i=0; i<=tot; ++i) ans=(ans+dp[tot][i])%mod;
printf("%lld\n", ans);
exit(0);
}
}
namespace task2{
int pre[N], lst[N], bkp[N], tot;
ll dp[N];
inline void upd(int i, ll dat) {dat%=mod; for (; i<=tot+1; i+=i&-i) md(dp[i], dat);}
inline ll query(int i) {ll ans=0; for (; i; i-=i&-i) md(ans, dp[i]); return ans;}
void solve() {
memset(lst, -1, sizeof(lst));
memcpy(bkp, c, sizeof(c));
for (int pos2=1; pos2<=n; ++pos2)
if (bkp[pos2-1]!=bkp[pos2]) c[++tot]=bkp[pos2];
for (int i=1; i<=tot; ++i) {
pre[i]=lst[c[i]];
lst[c[i]]=i;
}
upd(1, 1);
//cout<<"pre: "; for (int i=1; i<=tot; ++i) cout<<pre[i]<<' '; cout<<endl;
ll tem;
for (int i=1; i<=tot; ++i) if (~pre[i]) {
tem=query(pre[i]+1);
if (tem) upd(i+1, tem);
}
printf("%lld\n", query(tot+1));
exit(0);
}
}
signed main()
{
freopen("magic.in", "r", stdin);
freopen("magic.out", "w", stdout);
n=read();
for (int i=1; i<=n; ++i) c[i]=read();
task2::solve();
return 0;
}