A题意:给定字符串s,求无重复字符子序列个数(子序列相同位置不同算不同)

在最后加一串a~z表示选了这些就是不选这个字符了,然后答案就是每次选每个字符位置的方案数的积

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005,mod=1e9+7;
int n;
char s[N];
long long ans=1,a[30];
int main()
{
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++)
a[s[i]-'a']++;
for(int i=0;i<26;i++)
ans=ans*(a[i]+1)%mod;
printf("%lld\n",(ans-1+mod)%mod);
return 0;
}


B题意:给定一个颜色序列,可以操作0~inf次,每次操作选两个相同色把中间全涂成这个色

最后结果一定是若干个色块,设f[i]为涂完前i个并且i点保持原来颜色的方案数,枚举和i颜色相同的j表示涂这一段,f[i]=Σf[j-1],为避免重复计数,j-1和i必须不同色(保证色块最长),然后前缀和优化即可

#include<iostream>
#include<cstdio>
using namespace std;
const int N=200005,mod=1e9+7;
int n,a[N],f[N],s[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
f[0]=1,s[a[1]]=1;
for(int i=1;i<=n;i++)
{
// for(int j=1;j<=i;j++)
// if(a[i]==a[j]&&a[j-1]!=a[i])
// f[i]=(f[i]+f[j-1])%mod;
f[i]=s[a[i]];
if(a[i+1]!=a[i])
s[a[i+1]]=(s[a[i+1]]+f[i])%mod;
}
printf("%d\n",f[n]);
return 0;
}


C题意:给定n,s,t,求一个0~2^n-1的排列使得相邻两个数二进制下有且只有一个位不同,或者输出无解(格雷码那样)

首先st二进制下不同位有偶数个是无解,因为没走一位,和t二进制下不同位的数量的奇偶性就会变一次,最后第2^n-2个和t二进制下不同位的数量是偶数,不符合要求

然后证明其他的一定能构造出来,首先n=1是可行的,假设当先n=k都可以,那么证明n=k+1可以;

把st不同的最后一位抠掉(操作的时候是变成0),造出s't',设c为s'抠掉最后一位,d为c抠掉不同的最后一位,这样长为2^(n-1)的(s',c)和(d,t')就可以求了,递归实现

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,a,b;
void prin(int a,int b,int v)
{
if(a==b)
{
printf("%d ",a);
return;
}
int x=(a^b)&(-(a^b));
v^=x;
int y=v&(-v);
prin(a,a^y,v);
prin(a^y^x,b,v);
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
if(__builtin_popcount(a^b)&1)
{
puts("YES");
prin(a,b,(1<<n)-1);
}
else
puts("NO");
return 0;
}