今天又是考崩的一天呐~
呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐呐(大声)
签到题总是做不出来,哭哭了
T1:过河
你们出题啊,不要见得风就是雨,天天想搞大新闻。美国的华莱士比你们不知道高到哪里去了,我做他的题谈笑风声。出题当然吼啊,但是出这种签到题我还不会做,你们啊,I'm angry!
容易发现瓶颈就是能一步跳到的两个石块中间的距离,所以我们双指针取个 (min) 即可。
T2:选数
容易发现给出的式子就是将其循环左移一位,预处理前缀和和后缀和即可打出 (O(2^nm)) 的暴力。
我们可以把 (x) 的左移转化为前缀和的左移,所以后面 (pre[i]igoplus suf[i+1]) 就可以预处理出来放到一棵 01Trie 上。然后我们可以 dfs 得出答案。
(然后好像就是板子了,但考试的时候并没有想到 01Trie 这个东西)
当当前节点有两个儿子的时候,无论怎么选都是 (0),所以我们就直接递归两个儿子。
否则,如果只有一个儿子,skyh 一定可以操作使当前位与儿子相反从而获得当前位 (1) 的贡献,我们加上贡献然后继续递归即可。
当递归完最低位时,我们就可以更新答案了。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,Max=-1,cnt;
int a[maxn],pre[maxn],suf[maxn],b[maxn];
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
inline int Change(int x){
return ((x>>(n-1))+(x<<1))&((1<<n)-1);
}
int tot;
int ch[maxn<<5][2];
inline void Insert(int x){
int u=0;
for(int i=n-1;i>=0;i--){
int v=(x>>i)&1;
if(!ch[u][v])ch[u][v]=++tot;
u=ch[u][v];
}
}
void dfs(int u,int sum,int step){
if(step==0){
if(sum>Max){
Max=sum;cnt=1;
}else if(sum==Max)cnt++;
return;
}
if(ch[u][0]&&ch[u][1]){
dfs(ch[u][0],sum,step-1);
dfs(ch[u][1],sum,step-1);
}else if(ch[u][0]||ch[u][1]){
sum=sum+(1<<(step-1));
dfs(ch[u][0]?ch[u][0]:ch[u][1],sum,step-1);
}
}
int main(){
#ifndef LOCAL
freopen("choose.in","r",stdin);
freopen("choose.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=m;i++)
a[i]=read();
for(register int i=1;i<=m;i++)
pre[i]=pre[i-1]^a[i];
for(register int i=m;i>=1;i--)
suf[i]=suf[i+1]^a[i];
for(register int i=0;i<=m;i++){
b[i]=Change(pre[i])^suf[i+1];
Insert(b[i]);
}
dfs(0,0,n);
printf("%d
%d
",Max,cnt);
return 0;
}
T3:数列
还不会
T4:模板
还不会
ac.cpp