AGC031 A~C

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
",(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
",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;
}
原文地址:https://www.cnblogs.com/lokiii/p/10549227.html