设d[ i ][ j ][ k ] 为在第从1到第 i 个字母,后缀连续长度为 j (j=0为元音,1位辅音)的种类数,很显然转移方程为:
d[ i ][ 0 ][ j+1 ]=d[ i-1 ][ 0 ][ j ]*5,辅音则乘以21,d[ i ][ 0 ][ 1 ]=5*( d[ i-1 ][ 1 ][ k ](k=1,2,,,B)),还有一个读者自己可以推,很简单。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5005,mod=1e9+7;
ll d[maxn][2][55];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,a,b;
cin>>n>>a>>b;
ll ans=0;
for(int i=1;i<=n;i++)
{
ll res1=d[i-1][0][a],res2=d[i-1][1][b];
for(int j=1;j<a;j++)
if(i-j>=0)
d[i][0][j+1]=d[i-1][0][j]*5%mod,res1+=d[i-1][0][j],ans+=d[i][0][j+1];
for(int j=1;j<b;j++)
if(i-j>=0)
d[i][1][j+1]=d[i-1][1][j]*21%mod,res2+=d[i-1][1][j],ans+=d[i][1][j+1];
if(i==1)
res1=res2=1;
d[i][0][1]=res2*5%mod;
d[i][1][1]=res1*21%mod;
ans+=d[i][0][1];
ans+=d[i][1][1];
}
cout<<ans%mod<<endl;
}
}
思路:因为最多只有233种情况,所以我只要从A开始跑bfs即可,很简单。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int vis[250],d[250];
int dij(int s,int t)
{
queue<int>q;
q.push(s);
memset(vis,0,sizeof(vis));
d[s]=0;
while(!q.empty())
{
int x=q.front();q.pop();
int y=(x*x*x+x*x)%233;
if(!vis[y])
{
q.push(y);
d[y]=d[x]+1;
vis[y]=1;
if(y==t)return d[y];
}
y=(x*x*x-x*x)%233;
if(!vis[y])
{
q.push(y);
d[y]=d[x]+1;
vis[y]=1;
if(y==t)return d[y];
}
}
return -1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int a,b;
scanf("%d%d",&a,&b);
if(a==b)
{
puts("0");
continue;
}
if(b>=233)
{
puts("-1");
continue;
}
printf("%d\n",dij(a%233,b));
}
}
思路:比赛时题意读漏了,赛后发现加特判就过了(被自己蠢哭了),首先我们要快速求出所有歌曲的最长公共子串长度,看是否超过K,怎么求呢?还记得后缀数组的height数组吗,没错,我们把所有歌曲拼接成一个字符串,然后求后缀数组,然后枚举height数组把所有长度超过k的不同后缀串用G数组标记,最后状态压缩枚举所有状态,用G数组判断该状态是否合法即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=8e5+1000;
int G[25];
int id[maxn];
struct S_array
{
int sa[maxn],t[maxn],t2[maxn],c[maxn],n;
char s[maxn];
void build_sa(int m)
{
int i,*x=t,*y=t2;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[i]=s[i]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(i=n-k;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=0;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n)break;
m=p;
}
}
int rank[maxn],height[maxn];
void getHeight()
{
int i,j,k=0;
for(i=0;i<n;i++)rank[sa[i]]=i;
for(i=0;i<n;i++){
if(k)k--;
int j=sa[rank[i]-1];
while(s[i+k]==s[j+k])k++;
height[rank[i]]=k;
}
}
void ss(int k)
{
int vis[21],flag=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<n-1;i++)
if(height[i]>=k)
{
vis[id[sa[i]]]=1;
vis[id[sa[i-1]]]=1;
flag=1;
}
else if(flag)
{
flag=0;
for(int j=1;j<=20;j++)
for(int p=1;p<j;p++)
if(vis[j]&&vis[p])
G[j]|=(1<<p-1),G[p]|=(1<<j-1);
memset(vis,0,sizeof(vis));
}
}
}sa;
int main()
{
int n,k,m,x,cnt=0,mn=25,res=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&m);
if(m<k)res++;
for(int j=1;j<=m;j++)
scanf("%d",&x),id[cnt]=i,sa.s[cnt++]=x+25;
mn--;
sa.s[cnt++]=mn;
}
sa.n=cnt;
sa.build_sa(150);
sa.getHeight();
sa.ss(k);
int all=(1<<n)-1;
int ans=1;
for(int i=1;i<=all;i++)
{
int p=0,s=0;
for(int j=0;(1<<j)<=i;j++)
if(i&(1<<j))
s|=G[j+1],p++;
if((s^i)==all)
ans=max(ans,p);
}
ans-=res;
cout<<ans;
}