[CF1411E]Poman Numbers

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1411E]Poman Numbers相关的知识,希望对你有一定的参考价值。

Poman Numbers

题解

我们发现根据我们的 f ( S ) f(S) f(S)函数的表达式,可以发现,对于任意的 s i s_{i} si,它对答案的贡献只会是 + 2 s i − ′ a ′ +2^{s_{i}-'a'} +2sia或者 − 2 s i − ′ a ′ -2^{s_{i}-'a'} 2sia,也就是说,它跟前的系数只会是 + 1 +1 +1 − 1 -1 1
而一个数的正负相当于它被传进 − f ( S [ 1 , m ] ) -f(S[1,m]) f(S[1,m])的次数的奇偶性,我们可以将我们的函数执行的整个过程看作一棵二叉树的过程,往左儿子传就是 − - ,往右儿子传就是正 + + +,所有非叶节点均有 2 2 2个儿子。
那么,一个点系数的 ± \\pm ±就是由根走到该节点的路径上向左儿子走的次数。

由于 m m m是可以由我们定义的,我们当然可以调整这颗树的形态。
我们可以从叶子节点开始不断合并构造出这棵树。
对于点 n n n,它无论跟谁合并都是右儿子,所以它的系数只能是 + 1 +1 +1
对于点 n − 1 n-1 n1,它只有与 n n n合并时能成为左儿子,它又必须更 n n n合并一次,所以他的系数只能是 − 1 -1 1

对于 i ⩽ n − 2 i\\leqslant n-2 in2,它的系数既可以是 + 1 +1 +1也可以是 − 1 -1 1,下面给出一种构造方法。
它开始就与 i + 1 i+1 i+1合并,之后一直随 i + 1 i+1 i+1一起运动,这样的话它的左儿子次数只比 i + 1 i+1 i+1多最开始的 1 1 1,系数与 i + 1 i+1 i+1相反。
它也可以在 i + 1 i+1 i+1 i + 2 i+2 i+2合并后与 i + 1 i+1 i+1合并,由于 i + 1 i+1 i+1在合并 i i i i + 2 i+2 i+2之前不可能与任何数合并,所已它与 i + 2 i+2 i+2合并时只会成为一次左儿子, i i i现在合并进来,也只会成为一次左儿子,之后随 i + 1 i+1 i+1一起运动,系数与 i + 1 i+1 i+1相同。
所以,我们可以先对 t t t减去 2 s n − ′ a ′ − 2 s n − 1 − ′ a ′ 2^{s_{n}-'a'}-2^{s_{n-1}-'a'} 2sna2sn1a,再判断能否用其它数构造出 t t t

实际上我们可以贪心的方法判断我们是否能够构造出 t t t,这也是个相当经典的方法。
我们可以先将所有的 s i s_{i} si从大到小排序,再依次对 t t t进行操作,当 t < 0 t<0 t<0的时候让 t t t加上 2 s i − ′ a ′ 2^{s_{i}-'a'} 2sia t > 0 t>0 t>0的时候就减去。
如果最后 t t t 0 0 0,那么我们就可以构造出 t t t,否则不行。

时间复杂度 O ( n log ⁡   n ) O\\left(n\\log\\,n\\right) O(nlogn)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;     
const int INF=0x3f3f3f3f;  
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){putchar('\\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,sum[MAXN],a[MAXN];LL pow2[MAXN],T;
char str[MAXN];
signed main(){
	read(n);read(T);scanf("%s",str+1);
	pow2[0]=1;for(int i=1;i<26;i++)pow2[i]=pow2[i-1]+pow2[i-1];
	for(int i=1;i<=n;i++)a[i]=str[i]-'a';T-=(1LL<<a[n])-(1LL<<a[n-1]);
	int tp=0;sort(a+1,a+n-1);T=Fabs(T);LL now=0;
	for(int i=n-2;i>0;i--){
		if(now<=T)now+=pow2[a[i]];else now-=pow2[a[i]];
		//printf("%d:%d\\n",i,a[i]);	
	}
	if(now==T)puts("Yes");else puts("No");
	return 0;
}

谢谢!!!

以上是关于[CF1411E]Poman Numbers的主要内容,如果未能解决你的问题,请参考以下文章

[Algorithm] A nonrecursive algorithm for enumerating all permutations of the numbers {1,2,...,n}(代码片

CF449DJzzhu and Numbers

[CF 747F]Igor and Interesting Numbers

CF1245 A. Good ol' Numbers Coloring(java与gcd)

Vus the Cossack and Numbers CF-1186D(思维)

CF1447B Numbers Box