牛客OI月赛12-提高组

当天晚上被\(loli\)要求去打了某高端oj部分原创的模拟赛,第二天看了牛客的题觉得非常清真,于是就去写了

不难发现现场写出\(260\text{pts}\)并不需要动脑子,而且\(260\text{pts}\)甚至还有\(rk2\),感觉没打非常吃亏

A.小w的进制转换

大概理解一下就是询问\(1\)到\(n\)里有多少个数的二进制表示是反回文形式的,即对称位置是相反的,比如\(1001,101010\)

之后根据题意,这个反回文的二进制串长度必须是偶数(因为长度为奇数的串对称中心和对称中心不相反)

也不难发现这个反回文串确定了前一半后面就确定了

考虑枚举这个反回文的串的长度,显然长度小于\(n\)的长度的串,我们只需要让最高填\(1\),最低位填\(0\),之后除去最高位的前\(\frac{len-2}{2}\)随便填即可

对于长度等于\(n\)的串,还是最高填\(1\),最低位填\(0\),除去最高位的前\(\frac{len-2}{2}\)位填一个严格小于\(n\)的前\(\frac{len-2}{2}\)位的数,这样就能保证严格小于\(n\)

之后再特判一下前\(\frac{len-2}{2}\)位和\(n\)的前\(\frac{len-2}{2}\)位相等时的时候,反对称过去的数是否超过\(n\)

代码好像写得有点丑了

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
LL b[65];
LL n,ans;
inline void calc(int bit) {
if(bit&1) return;
ans+=(1ll<<((bit-2)/2));
}
int a[64];int tot;
inline int solve() {
b[0]=1;int W=2*tot+1;
for(re int i=0;i<=tot;++i) b[W-i]=b[i]^1;
LL m=0;
for(re int i=0;i<=W;++i)
m<<=1ll,m|=b[i];
return m<=n;
}
inline void Calc() {
scanf("%lld",&n);;
int now=0;tot=0;ans=0;
for(re LL i=63;i>=0;--i) {
if(!now) {
if(n>>i&1) {
now=1;
if((i-1)&1) continue;
for(re LL j=i-1;j>=0;--j) {
if(tot*2>=i-1) continue;
b[++tot]=n>>j&1;
}
LL k=0;
for(re LL j=1;j<=tot;++j)
k|=b[j],k<<=1ll;
k>>=1ll;ans=k;
if(!tot) ++ans;else ans+=solve();
}
continue;
}
if(i>0) calc(i+1);
}
std::cout<<ans;puts("");
}
int main() {
int T;scanf("%d",&T);
while(T--) Calc();
return 0;
}

B.小doge的快乐阳光跑

题意:给一张图,求一个权值和路径最小的移动序列,使得移动序列包含两个给定的子序列。

发现点数只有\(10^3\),边数也只有\(10^4\),图相当稀疏,所以完全可以跑\(n\)遍单源最短路,求出所有点对的之间的最短路

之后搞一个\(dp\)就完事了,设\(dp_{0/1,i,j}\)表示当前在第\(1/2\)个子序列的第\(i\)个位置,另一个子序列已经经过了前\(j\)个位置

转移显然,就是枚举一下下一个点去哪里

#include<bits/stdc++.h>
#define re register
#define LL long long
#define mp std::make_pair
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
typedef std::pair<int,int> pii;
const int maxn=1e3+5;
struct E{int v,nxt,w;}e[maxn*20];
int d[maxn][maxn];
int n,m,num,head[maxn],vis[maxn],a[maxn],b[maxn],A,B;
inline void add(int x,int y,int w) {
e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=w;
}
LL dp[2][105][105];
std::priority_queue<pii,std::vector<pii>,std::greater<pii> > q;
inline void Dij(int s) {
for(re int i=1;i<=n;++i) d[s][i]=1e9,vis[i]=0;
d[s][s]=0,q.push(mp(d[s][s],s));
while(!q.empty()) {
int k=q.top().second;q.pop();
if(vis[k]) continue;vis[k]=1;
for(re int i=head[k];i;i=e[i].nxt)
if(d[s][e[i].v]>d[s][k]+e[i].w) {
d[s][e[i].v]=d[s][k]+e[i].w;
q.push(mp(d[s][e[i].v],e[i].v));
}
}
}
int main() {
n=read(),m=read();
for(re int x,y,z,i=1;i<=m;i++)
x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
for(re int i=1;i<=n;i++) Dij(i);
A=read();for(re int i=1;i<=A;i++) a[i]=read();
B=read();for(re int i=1;i<=B;++i) b[i]=read();
memset(dp,20,sizeof(dp));
dp[0][1][0]=0,dp[1][0][1]=0;
for(re int t=1;t<A+B;++t)
for(re int j=0;j<=t&&j<=A;++j) {
re int k=t-j;
if(k>B) continue;
if(j<A) dp[0][j+1][k]=min(dp[0][j+1][k],dp[0][j][k]+d[a[j]][a[j+1]]),
dp[0][j+1][k]=min(dp[0][j+1][k],dp[1][j][k]+d[b[k]][a[j+1]]);
if(k<B) dp[1][j][k+1]=min(dp[1][j][k+1],dp[0][j][k]+d[a[j]][b[k+1]]),
dp[1][j][k+1]=min(dp[1][j][k+1],dp[1][j][k]+d[b[k]][b[k+1]]);
}
printf("%lld\n",min(dp[1][A][B],dp[0][A][B]));
return 0;
}

C.区间异或和异或区间最大值异或区间最小值

题意就是在给定的一个序列里找到一个区间,让上面那个东西最大

有\(60\rm pts\)是送的,写几个\(\rm subtask\)拼一拼就有了

考虑正解,考虑率大力分治一波,对于区间\([l,r]\)我们考虑一下如何合并\([l,mid]\)和\([mid+1,r]\)

我们把左区间所有后缀以及右区间所有前缀的异或和、最大值、最小值都扫出来,我们提前把最大值和最小值都给异或进去

考虑合并掉两个区间之后,两个最大值中较小的那一个就不是最大值了,我们需要把它异或回来;两个最小值中较大的也不是最小值了,也需要把它异或回来

于是我们考虑从右区间里拿出一个数来,作为最大值较小的去和左区间匹配

显然可以排序之后利用单调性开一个指针,把左区间比这个最大值大的都扫进来,放到一个数据结构里,显然这种数据结构是\(trie\)

之后按照最小值讨论一波

  • 左区间的最小值作为最小值,那么我们需要把右区间的最小值给异或回来,去查最小值小于右区间最小值中,异或上这个数最大的

  • 右区间的最小值作为最小值,那么需要把左区间的最小值给异或回来,我们可以对左区间维护一个把最小值异或回来的\(trie\),在这个\(trie\)里查最小值大于右区间最小值中,异或上这个数最大的

我们发现按照最大值把这些数加入\(trie\)的过程中最小值也是单调的,于是把\(trie\)可持久化一下就可以查区间异或最大值了

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#pragma GCC optimize(3)
#pragma GCC optimize("-fcse-skip-blocks")
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=1e5+5;
const int Bit=30;
struct Seg {int mn,mx,x;}b[2][maxn];
int n,a[maxn],c[maxn],cnt,tot,ans;
int rt[2][maxn],son[maxn*32][2],d[maxn*32];
inline int max(int a,int b) {return a>b?a:b;}
inline int min(int a,int b) {return a<b?a:b;}
int ins(int pre,int x,int w) {
int now=++cnt;
d[now]=d[pre]+1;
if(w==-1) return now;
son[now][0]=son[pre][0],son[now][1]=son[pre][1];
son[now][x>>w&1]=ins(son[pre][x>>w&1],x,w-1);
return now;
}
int query(int p1,int p2,int x,int w) {
if(w==-1) return 0;
int t=x>>w&1;
int now=d[son[p2][t^1]]-d[son[p1][t^1]];
if(now) return (1<<w)+query(son[p1][t^1],son[p2][t^1],x,w-1);
return query(son[p1][t],son[p2][t],x,w-1);
}
inline int find(int x) {
int l=1,r=tot,now=0;
while(l<=r) {
int mid=l+r>>1;
if(c[mid]<=x) l=mid+1,now=mid;
else r=mid-1;
}
return now;
}
void solve(int l,int r) {
if(l==r) return;
int mid=l+r>>1;
solve(l,mid),solve(mid+1,r);
int lenl=mid-l+1,lenr=r-mid;
for(re int i=mid+1;i<=r;++i) {
b[0][i-mid].mn=min(a[i],b[0][i-1-mid].mn);
b[0][i-mid].mx=max(a[i],b[0][i-1-mid].mx);
b[0][i-mid].x=a[i]^b[0][i-mid-1].x;
}
for(re int i=mid;i>=l;--i) {
b[1][mid+1-i].mn=min(a[i],b[1][mid-i].mn);
b[1][mid+1-i].mx=max(a[i],b[1][mid-i].mx);
b[1][mid+1-i].x=a[i]^b[1][mid-i].x;
}
for(re int i=1;i<=lenl;++i) b[1][i].x^=(b[1][i].mn^b[1][i].mx);
for(re int i=1;i<=lenr;++i) b[0][i].x^=(b[0][i].mn^b[0][i].mx);
cnt=0,tot=0;int now=lenl;
for(re int i=lenr;i;--i) {
while(now&&b[1][now].mx>=b[0][i].mx) {
++tot;
rt[0][tot]=ins(rt[0][tot-1],b[1][now].x,Bit);
rt[1][tot]=ins(rt[1][tot-1],b[1][now].x^b[1][now].mn,Bit);
c[tot]=b[1][now--].mn;
}
if(tot) {
int x=find(b[0][i].mn);
ans=max(ans,query(rt[0][0],rt[0][x],b[0][i].x^b[0][i].mx^b[0][i].mn,Bit));
ans=max(ans,query(rt[1][x],rt[1][tot],b[0][i].x^b[0][i].mx,Bit));
}
}
for(re int i=1;i<=tot;i++) rt[0][i]=rt[1][i]=0;
cnt=0;tot=0;now=lenr;
for(re int i=lenl;i;--i) {
while(now&&b[0][now].mx>=b[1][i].mx) {
++tot;
rt[0][tot]=ins(rt[0][tot-1],b[0][now].x,Bit);
rt[1][tot]=ins(rt[1][tot-1],b[0][now].x^b[0][now].mn,Bit);
c[tot]=b[0][now--].mn;
}
if(tot) {
int x=find(b[1][i].mn);
ans=max(ans,query(rt[0][0],rt[0][x],b[1][i].x^b[1][i].mx^b[1][i].mn,Bit));
ans=max(ans,query(rt[1][x],rt[1][tot],b[1][i].x^b[1][i].mx,Bit));
}
}
for(re int i=1;i<=tot;i++) rt[0][i]=rt[1][i]=0;
}
int main() {
n=read();
for(re int i=1;i<=n;i++) a[i]=read(),ans=max(ans,a[i]);
b[0][0].mn=b[1][0].mn=1e9;
solve(1,n);
printf("%d\n",ans);
return 0;
}

牛客OI月赛12-提高组题解的更多相关文章

  1. Nowcoder | [题解-N210]牛客OI月赛2-提高组

    比赛连接戳这里^_^ 我才不会说这是我出的题(逃) 周赛题解\((2018.10.14)\) \(T1\) \(25\sim50\)分做法\(:\)直接爆搜 作为一个良心仁慈又可爱的出题人当然\(T1 ...

  2. 牛客OI周赛9-提高组题目记录

    牛客OI周赛9-提高组题目记录 昨天晚上做了这一套比赛,觉得题目质量挺高,而且有一些非常有趣而且非常清奇的脑回路在里边,于是记录在此. T1: 扫雷 题目链接 设 \(f_i\) 表示扫到第 \(i\ ...

  3. 牛客OI周赛8-提高组A-用水填坑

    牛客OI周赛8-提高组A-用水填坑 题目 链接: https://ac.nowcoder.com/acm/contest/403/A 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制: ...

  4. 牛客小白月赛12 F 华华开始学信息学 (分块+树状数组)

    链接:https://ac.nowcoder.com/acm/contest/392/F来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 32768K,其他语言65536K ...

  5. 牛客网 牛客小白月赛12 B.华华教月月做数学-A^B mod P-快速幂+快速乘

    链接:https://ac.nowcoder.com/acm/contest/392/B来源:牛客网 华华教月月做数学 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其 ...

  6. 牛客OI周赛2-提高组

    A.游戏 链接:https://www.nowcoder.com/acm/contest/210/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语 ...

  7. 牛客OI周赛11-普及组 B Game with numbers (数学,预处理真因子)

    链接:https://ac.nowcoder.com/acm/contest/942/B 来源:牛客网 Game with numbers 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C+ ...

  8. 牛客OI周赛7-提高组 A 小睿睿的等式

    链接:https://ac.nowcoder.com/acm/contest/371/A来源:牛客网 小睿睿在游戏开始时有n根火柴棒,他想知道能摆成形如“A+B=n”的等式且使用的火柴棒数也恰好等于n ...

  9. 牛客OI周赛7-提高组 B小睿睿的询问(ST打表)

    链接:https://ac.nowcoder.com/acm/contest/371/B来源:牛客网 小睿睿的n个妹纸排成一排,每个妹纸有一个颜值val[i].有m个询问,对于每一个询问,小睿睿想知道 ...

随机推荐

  1. Leetcode_415字符串相加

    给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和. 注意: ①num1 和num2 的长度都小于 5100.②num1 和num2 都只包含数字 0-9.③num1 和num2 都不 ...

  2. docker volume持久化存储与数据分享

    第一种 指定volume文件mysql存储,存储的位置为/var/lib/mysql -v mysql:/var/lib/mysql 第二种 同步文件,将容器中的skeleton文件夹的内容同步到宿主 ...

  3. 在我的Mint上安装网易云音乐

    首先到网易官网下载Ubuntu版本的安装包,哪个版本多少位没多大所谓啦 然而会出现类似如下的依赖错误: dpkg: 依赖关系问题使得 netease-cloud-music 的配置工作不能继续: ne ...

  4. sql server 事务隔离性 snapshot 、read committed说明

    一. --该 read committed 默认事务隔离级别 在 systemuser修改事务未完成时 select * from [SystemUser] where id=62; 该语句是不可读取 ...

  5. LeetCode Array Easy 88. Merge Sorted Array

    Description Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted ar ...

  6. shell egrep 引号

    [jg73178@hdcgcgdbsla01dv ~]$ egrep \'SI\' tt.txt 'SI' [jg73178@hdcgcgdbsla01dv ~]$ egrep \"SI\& ...

  7. JSON.parse 解析json字符串时,遇字符串换行符,解析失败

    今天遇到json字符串转对象时报错了,发现有个字符串有换行符,仔细找了原因. 结果是因为JSON.parse转json字符串时遇到一些特殊字符需要先转义,如图所示 然后尝试了各路大神介绍的办法,均不适 ...

  8. 2019计蒜之道初赛第3场-阿里巴巴协助征战SARS 费马小定理降幂

    题目链接:https://nanti.jisuanke.com/t/38352 发现规律之后就是算ans=2^(n-1)+4^(n-1).但是注意到n十分大是一个长度为1e5的数字.要想办法降幂. 我 ...

  9. 前缀和+排序——cf1043E

    先不考虑第二个条件 要求i和所有其他人的分数和最小,选择x还是y,可以推出一个公式,即差xi-yi小的j都选y,反之都选x 那么按照xi-yi排序即可 然后再考虑第二个条件,做减法就行 /* xi+y ...

  10. Linux环境安装PHP链接SQLserver2008

    网上很多介绍,但是跟着做总是有问题,找到一个大神的,没出现过问题: 1.首先需要编译安装FreeTDS 1.1.安装 说明:一定要从官网下载最新的版本FreeTDS-0.95 ftp://ftp.fr ...