[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'}
+2si−′a′或者
−
2
s
i
−
′
a
′
-2^{s_{i}-'a'}
−2si−′a′,也就是说,它跟前的系数只会是
+
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
n−1,它只有与
n
n
n合并时能成为左儿子,它又必须更
n
n
n合并一次,所以他的系数只能是
−
1
-1
−1。
对于
i
⩽
n
−
2
i\\leqslant n-2
i⩽n−2,它的系数既可以是
+
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'}
2sn−′a′−2sn−1−′a′,再判断能否用其它数构造出
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'}
2si−′a′,
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}(代码片
[CF 747F]Igor and Interesting Numbers
CF1245 A. Good ol' Numbers Coloring(java与gcd)