2019 CCPC 网络选拔赛 部分题解
目录
2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛
6702 ^&^
\(1&1\)的话,\(c\)就必须为\(1\)。其他的贪心选\(0\).
注意c为正整数,0的话就取最低位1.
#include <iostream>
#define ll long long
using namespace std;
void solve(ll a,ll b) {
ll c=0;
for(ll i=31;i>=0;--i) {
bool k1=a&(1LL<<i),k2=b&(1LL<<i);
if(k1==1&&k2==1) c|=1LL<<i;
} if(c) return cout<<c<<"\n",void();
for(ll i=31;i>=0;--i) {
bool k1=a&(1LL<<i),k2=b&(1LL<<i);
if(k1||k2) c=1LL<<i;
} cout<<c<<"\n";
}
int main() {
int T;
cin>>T;
while(T --> 0) {
ll a,b;
cin>>a>>b;
solve(a,b);
}
return 0;
}
6703 array
修改操作其实是删除操作。
考虑不删除的话,就是把删除的数字放入\(set\)中
最终答案就是不删除的\(ans\)和\(set\)中符合条件的取个最小值。
方法一
建立主席树维护区间和。
二分,主席树\(check\)。
复杂度\(O(nlog^2n)\),实测\(T\)飞。
方法二
主席树上二分。
主席树不变查询区间和。然后找到第一个包含的满足条件的子区间。
条件就是\(r-l+1 < e[rt].tot\),然后再在这个区间上查一次就行了。
复杂度都是\(O(nlogn)\)
问了个当场切的老哥的代码,直接线段树,也没\(set\)直接改,我这里先\(Orz\)了。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <set>
#define ls(x) e[x].l
#define rs(x) e[x].r
#define _ 100007
using namespace std;
inline char nc() {
static char buf[3000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread (buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,m,a[_],cnt,rt[_];
set<int> dsr;
struct node{int l,r,siz;}e[_*20];
void insert(int l,int r,int pos,int val,int x,int &y) {
e[y=++cnt]=e[x];
e[y].siz++;
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) insert(l,mid,pos,val,ls(x),ls(y));
else insert(mid+1,r,pos,val,rs(x),rs(y));
}
int lastans,flag;
int ask(int l,int r,int x) {
if(l==r) return l;
int mid=(l+r)>>1;
if(e[ls(x)].siz<mid-l+1) return ask(l,mid,ls(x));
else return ask(mid+1,r,rs(x));
}
void query(int l,int r,int L,int R,int x) {
if(L<=l) {
if(!flag&&e[x].siz!=r-l+1) {
flag=1,lastans=min(lastans,ask(l,r,x));
} return;
}
int mid=(l+r)>>1;
if(L<=mid&&!flag) query(l,mid,L,R,ls(x));
if(R>mid&&!flag) query(mid+1,r,L,R,rs(x));
}
int main() {
int T=read();
while(T --> 0) {
dsr.clear(),dsr.insert(0x3f3f3f3f);
cnt=0;
for(int i=1;i<=n;++i) rt[i]=0;
for(int i=1;i<=cnt;++i) e[i]={};
n=read(),m=read();
for(int i=1;i<=n;++i) a[i]=read(),insert(1,n+1,a[i],a[i],rt[i-1],rt[i]);
rt[n+1]=rt[n];
lastans=0;
for(int i=1;i<=m;++i) {
int opt=read();
if(opt==1) {
int pos=read()^lastans;
if(!dsr.count(a[pos])) dsr.insert(a[pos]);
} else {
int r=read()^lastans,k=read()^lastans;
lastans=*dsr.lower_bound(k),flag=0;
query(1,n+1,k,n+1,rt[r]);
printf("%d\n",lastans);
}
}
}
return 0;
}
6704 K-th occurrence
想了想,只会后缀数组+二分+主席树,感觉有点恐怖就没写,最后还是写了。
然后套了个后缀数组板子就过了,实现还是挺简单的一点也不恐怖。
#include <bits/stdc++.h>
using namespace std;
const int _=2e5+7;
int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,Q,rt[_];
char s[_];
namespace SA {
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define ROF(i,a,b) for(int i=a;i>=b;--i)
int sa[_],rk[_],c[_],x[_],height[_],st[_][21];
void clear() {
memset(sa,0,sizeof(sa));
memset(rk,0,sizeof(rk));
memset(c,0,sizeof(c));
memset(x,0,sizeof(x));
memset(height,0,sizeof(height));
memset(st,0,sizeof(st));
}
void get_sa() {
int m=300;
FOR(i,1,n) ++c[rk[i]=s[i]];
FOR(i,1,m) c[i]+=c[i-1];
ROF(i,n,1) sa[c[rk[i]]--]=i;
for(int k=1;k<=n;k<<=1) {
int p=0;
FOR(i,n-k+1,n) x[++p]=i;
FOR(i,1,n) if(sa[i]>k) x[++p]=sa[i]-k;
FOR(i,1,m) c[i]=0;
FOR(i,1,n) ++c[rk[i]];
FOR(i,1,m) c[i]+=c[i-1];
ROF(i,n,1) sa[c[rk[x[i]]]--]=x[i],x[i]=0;
swap(rk,x);
rk[sa[1]]=1,p=1;
FOR(i,2,n) rk[sa[i]]=(x[sa[i]]==x[sa[i-1]]&&x[sa[i]+k]==x[sa[i-1]+k]) ? p : ++p;
if(p==n) break;
m=p;
}
}
void get_height() {
FOR(i,1,n) rk[sa[i]]=i;
int k=0;
FOR(i,1,n) {
k=k?k-1:0;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]&&i+k<=n&&j+k<=n) k++;
height[rk[i]]=k;
}
height[0]=0;
FOR(i,1,n) st[i][0]=height[i];
FOR(j,1,20)
for(int i=1;i+(1<<j)-1<=n;++i)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int LCP(int i,int j) {
if(i-1==j) return n-sa[i-1]+1;
int x=log2(j-i+1);
return min(st[i][x],st[j-(1<<x)+1][x]);
}
}
namespace TREE {
#define ls(x) e[x].l
#define rs(x) e[x].r
struct node {int l,r,siz;}e[_*32];
int cnt;
void insert(int l,int r,int L,int x,int &y) {
e[y=++cnt]=e[x];
e[y].siz++;
if(l==r) return;
int mid=(l+r)>>1;
if(L<=mid) insert(l,mid,L,ls(x),ls(y));
else insert(mid+1,r,L,rs(x),rs(y));
}
int query(int l,int r,int k,int x,int &y) {
if(l==r) return l;
int mid=(l+r)>>1,w=e[ls(y)].siz-e[ls(x)].siz;
if(k<=w) return query(l,mid,k,ls(x),ls(y));
else return query(mid+1,r,k-w,rs(x),rs(y));
}
}
void solve(int S,int T,int k) {
int L,R,l,r;
l=1,r=SA::rk[S];
while(l<=r) {
int mid=(l+r)>>1;
if(SA::LCP(mid+1,SA::rk[S])>=T-S+1) L=mid,r=mid-1;
else l=mid+1;
}
l=SA::rk[S],r=n;
while(l<=r) {
int mid=(l+r)>>1;
if(SA::LCP(SA::rk[S]+1,mid)>=T-S+1) R=mid,l=mid+1;
else r=mid-1;
}
// cout<<SA::rk[S]<<"\n";
// cout<<L<<" "<<R<<"\n";
if(R-L+1<k) return puts("-1"),void();
printf("%d\n",TREE::query(1,n,k,rt[L-1],rt[R]));
}
int main() {
int T=read();
while(T --> 0) {
//clear
memset(rt,0,sizeof(rt));
memset(TREE::e,0,sizeof(TREE::e));
TREE::cnt=0;
SA::clear();
//init
n=read(),Q=read();
scanf("%s",s+1);
n=strlen(s+1);
SA::get_sa();
SA::get_height();
for(int i=1;i<=n;++i) TREE::insert(1,n,SA::sa[i],rt[i-1],rt[i]);
//debug
// puts("sa : ");
// for(int i=1;i<=n;++i) cout<<SA::sa[i]<<" ";
// puts("\nrk : ");
// for(int i=1;i<=n;++i) cout<<SA::rk[i]<<" ";
// cout<<"\n";
// puts("LCP");
// for(int i=1;i<=n;++i) {
// for(int j=1;j<=n;++j) {
// if(i>j) printf("0 ");
// else printf("%d ",SA::LCP(i+1,j));
// }
// printf("\n");
// }
//query
while(Q --> 0) {
int l=read(),r=read(),k=read();
solve(l,r,k);
}
}
return 0;
}
6705 path
6706 huntian oy
6707 Shuffle Card
想了半天也不会啊,平衡树还很麻烦,不想写。
其实倒着做就行了。
#include <bits/stdc++.h>
using namespace std;
const int _=2e5+7;
int n,m,a[_],b[_],vis[_];
vector<int> ans;
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=m;++i) scanf("%d",&b[i]);
for(int i=m;i>=1;--i) {
if(vis[b[i]]) continue;
vis[b[i]]=1;
ans.push_back(b[i]);
}
for(int i=1;i<=n;++i) {
if(vis[a[i]]) continue;
ans.push_back(a[i]);
}
for(int i=0;i<n;++i) cout<<ans[i]<<" ";
return 0;
}
6708 Windows Of CCPC
这是\(yjg\)外出模拟赛的\(luogu\)原题啊,\(axm\)还拉我做过,把\(0,1\)改成了\(C,P\)了而已。
递归即可。
#include <bits/stdc++.h>
using namespace std;
const int _=1207;
int n,A[_][_];
void copp(int x,int y,int len) {
for(int i=0;i<len;++i)
for(int j=0;j<len;++j)
A[x+i][y+j]=A[i][j];
}
void print(int x) {
for(int i=0;i<(1<<x);++i) {
for(int j=0;j<(1<<x);++j)
printf("%c",A[i][j]?'C':'P');
printf("\n");
}
}
void calc(int n) {
if(n==0) return A[0][0]=1,void();
calc(n-1);
int len=1<<(n-1);
copp(0,len,len);
copp(len,len,len);
for(int i=0;i<len;++i)
for(int j=0;j<len;++j)
A[len+i][j]=A[i][j]^1;
}
int main() {
int T;
cin>>T;
while(T-->0) {
int x;cin>>x;
calc(x);
print(x);
}
}
6709 Fishing Master
啊,想了好久,好笨啊。
考虑dp,不会。贪心。
首先一开始肯定要先捉一次鱼。
发现捉鱼分两种种。
1.煮鱼的时间内能去捉鱼并且在锅里鱼没熟之前回来。
2.煮鱼的时间内能去捉鱼并且在锅里鱼熟之后时候回来。
显然1这种情况能干就干,相当于一开始就捉到了这些条。
剩下的捕鱼就得是情况2了,因为剩下的煮鱼时间都是小于捕鱼时间的,当然是贪心的从煮鱼时间大的开始捉。
发现这样一定能安排上(先捉情况2,然后过程中能捉1就捉1)。
然后就做完了。
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int _=2e5+7;
ll n,m,t[_];
int main() {
std::ios::sync_with_stdio(false);
ll T;
cin>>T;
while(T --> 0) {
cin>>n>>m;
for(ll i=1;i<=n;++i) cin>>t[i];
sort(t+1,t+1+n);
ll ma=0,ans=0;
for(ll i=1;i<=n;++i) ma+=t[i]/m;
for(ll i=1;i<=n;++i) ans+=t[i];
ans+=m;
if(ma>=n-1) {
cout<<ans<<"\n";
} else {
ll need=n-1-ma;
for(ll i=1;i<=n;++i) t[i]-=t[i]/m*m;
sort(t+1,t+1+n);
for(ll i=n;i>=1;--i) {
need--;
ans+=m-t[i];
if(!need) break;
}
cout<<ans<<"\n";
}
}
}
6710 Kaguya
6711 Touma Kazusa's function
6712 sakura
原文地址:https://www.cnblogs.com/dsrdsr/p/11406004.html
- Nmap扫描对比工具–libnmap实践
- 如何使用TensorFlow实现神经网络
- 安全科普:详解流量劫持的形成原因
- Office”组合”式漏洞攻击样本分析
- jsp标签小结
- 专家解释“愤怒的小鸟”如何变身间谍
- BT5 + wireshark玩wifi捕获和中间人攻击
- Hibernate HQL注入攻击入门
- 高效开源的网络扫描框架NINJA-PingU
- 对List.Sort的简单研究
- 使用Apache API监控Uber的实时数据,第3篇:使用Vert.x的实时仪表板
- 走进科学:我是如何“黑了”星级酒店的
- OpenSSL空指针引用do_ssl3_write
- 针对近期“博全球眼球的OAuth漏洞”的分析与防范建议
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法