LibreOJ β Round #2 题解

模拟只会猜题意

题目:

$1 \leq x \leq n \leq 10^4,m \leq 10^5,|A_i| \leq 10^4$

题解:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 10010;
int a[maxn],anss[maxn],s[maxn];
int main(){
rep(i,1,n){
anss[i] = -0x3f3f3f3f;
}
rep(x,1,n){
int y = -0x3f3f3f3f;
rep(i,1,n-x+1){
y = max(y,s[i+x-1]-s[i-1]);
}anss[x] = y;
}
per(i,n-1,1) anss[i] = max(anss[i],anss[i+1]);
while(m--){
printf("%d\n",anss[x]);
}
return 0;
}



贪心只能过样例

题目:

$S = \sum x_i^2$，求 $S$ 的种类数.
$1 \leq n,a_i,b_i \leq 100$

题解:

#include <cstdio>
#include <bitset>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 109;
int n,m,x[maxn],y[maxn];
bitset<1000100> s,t;
int main(){
rep(i,1,n){
rep(j,x[i]+1,y[i]) t |= (s << j*j);
s = t;
}
int ans = 0;
rep(i,1,1000000) if(t[i]) ++ans;
printf("%d\n",ans);
return 0;
}



DP 一般看规律

题目:

$1 \leq n,m \leq 10^5$，元素大小在 int 范围内.

题解:

#include <set>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 100010;
set<int>S[maxn];
map<int,int>mp;
int main(){
int cnt = 0,x;
rep(i,1,n){
if(!mp.count(x)) mp[x] = ++ cnt;
S[mp[x]].insert(i);
}
int ans = 2147483647;
rep(i,1,cnt){
if(S[i].empty()) continue;
for(set<int>::iterator it = S[i].begin(),t = (it++);it != S[i].end();++ it,++ t){
ans = min(ans,(*it) - (*t));
}
}
while(m--){
if(mp.count(x) && mp.count(y)){
int idx = mp[x],idy = mp[y];
if(S[idx].size() > S[idy].size()){
mp[x] = idy;mp[y] = idx;
}
idx = mp[x],idy = mp[y];
if(idx == idy){printf("%d\n",ans);continue;}
for(set<int>::iterator it = S[idx].begin();it != S[idx].end();++ it){
set<int>::iterator tt = S[idy].insert(*it).first;
if(tt != S[idy].begin()) (--tt),ans = min(ans,*it - *tt),(++tt);
(++tt);
if(tt != S[idy].end()) ans = min(ans,*tt - *it);
}S[idx].clear();
}else if(mp.count(x)){
mp[y] = mp[x];mp.erase(x);
}
printf("%d\n",ans);
}
return 0;
}


计算几何瞎暴力

题目:

1. 在数组 $A$ 的末尾添加一个数 $x$.
2. $\sum_{i=l}^rA_i$
3. 将数组 $A$ 中的每个数 $A_i \to A_i \oplus x$
4. 将数组 $A$ 从小到大排序.

$1 \leq n,m \leq 10^5,0 \leq x,A_i \leq 10^9$

题解:

$($根据全局的 $X$ 考虑每个二进制位累加进 $ans$ 即可$)$.

$Trie$ 上打下的全局异或标记只是改变了相对的大小关系.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 200010;
const int maxV = 31;
struct Node{
Node *ch[2];
int siz,ws[maxV];
}mem[maxn*maxV],*it,*root,*null;
inline Node* newNode(){
Node *p = it++;p->ch[0] = p->ch[1] = null;
p->siz = 0;return p;
}
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null;
null->siz = 0;root = newNode();
}
int sum[maxn][maxV],a[maxn];
int tot_tag,swap_tag,cnt,snum;
inline void insert(int x){
Node *p = root;++ snum;
per(i,maxV-1,0){
if(p->ch[(x >> i)&1] == null) p->ch[(x >> i)&1] = newNode();
p = p->ch[(x >> i)&1];++ p->siz;
rep(j,0,maxV-1) p->ws[j] += (x >> j) & 1;
}return ;
}
inline void push(int x){
a[++cnt] = x;
rep(i,0,maxV-1) sum[cnt][i] = sum[cnt-1][i] + ((x >> i)&1);
}
inline void rebuild(){
while(cnt) insert(a[cnt--]);swap_tag = tot_tag;
}
inline ll find(int k){
Node *p = root;ll res = 0;
per(i,maxV-1,0){
if(k == 0) break;
if(k < p->ch[(swap_tag >> i)&1]->siz){
p = p->ch[(swap_tag >> i)&1];
}else{
Node *q = p->ch[(swap_tag >> i)&1];k -= q->siz;
rep(j,0,maxV-1){
if((tot_tag >> j)&1) res += (ll)(q->siz - q->ws[j]) << j;
else res += (ll)q->ws[j] << j;
}p = p->ch[(swap_tag >> i)&1^1];
}
}
rep(i,0,maxV-1){
if( ((tot_tag >> i)&1) && p->ws[i] == 0) res += (ll)k << i;
if( ((tot_tag >> i)&1) == 0 && p->ws[i]) res += (ll)k << i;
}return res;
}
inline ll query(int x){
if(x <= snum) return find(x);
ll res = find(snum);x -= snum;
rep(i,0,maxV-1){
if((tot_tag >> i) & 1) res += (ll)(x - sum[x][i]) << i;
else res += (ll)sum[x][i] << i;
}return res;
}
int main(){
while(m--){
else if(op == 2){
printf("%lld\n",query(y) - query(x-1));
}else if(op == 3) read(x),tot_tag ^= x;
else rebuild();
}
return 0;
}


数论只会 GCD

题目:

$1 \leq n,m \leq 100000$,所有的元素在 int 范围之内, $\sum len_i \leq 100000$

题解:

$包含任一特定元素 = 全局 - 不包含特定元素$

$包含任一特定元素 = f(len) - \sum_{i=1}^{m+1}f(a_i - a_{i-1}+1)$

• $f(n) = \frac{n(n+1)}{n}$ , 即长度为 $n$ 的序列的子段个数.
• $a_i$ 表示该元素第 $i$ 次出现的位置并假设第一次出现于 $0$ 最后一次出现于 $n+1$.

#include <set>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <algorithm>
using namespace std;
typedef long long ll;
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
typedef pair<int,int> pa;
const int maxn = 200010;
const int mod = 19260817;
inline int F(int L){return (int)(1LL*L*(L+1)/2LL%mod);}
int S[maxn],T[maxn],cnt,a[maxn];
int tmp[maxn];
struct save{int x,y,z;}c[maxn];
struct Node{
Node *ch[2];
int w;
}*root[maxn],mem[maxn*30],*it,*null;
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null;
null->w = 0;root[0] = null;
}
inline Node* newNode(){
Node *p = it++;
p->ch[0] = p->ch[1] = null;
p->w = 0;return p;
}
Node* build(int l,int r){
Node *p = newNode();
if(l == r){
p->w = F(T[l] - S[l] + 1);
return p;
}int mid = l+r >> 1;
p->ch[0] = build(l,mid);
p->ch[1] = build(mid+1,r);
p->w = 1LL*p->ch[0]->w*p->ch[1]->w % mod;
return p;
}
Node* modify(Node *rt,int l,int r,int pos,int v){
Node *p = it++;*p = *rt;
if(l == r){
p->w += v;
if(p->w >= mod) p->w -= mod;
return p;
}int mid = l+r >> 1;
if(pos <= mid) p->ch[0] = modify(p->ch[0],l,mid,pos,v);
else p->ch[1] = modify(p->ch[1],mid+1,r,pos,v);
p->w = 1LL*p->ch[0]->w*p->ch[1]->w % mod;
return p;
}
set<int>s[maxn];int ans = 0,n;
inline void insert(int x,int y,int v,int f){
set<int>::iterator it;
if(f == 0) it = s[v].find(S[x]+y-1),assert(it != s[v].end());
else it = s[v].insert(S[x]+y-1).first;
int l = 0,r = T[x] - S[x] + 2;
if(it != s[v].begin()){
if(*(--it) >= S[x]) l = *it - S[x] + 1;
++ it;
}
if((++ it) != s[v].end()){
if(*it <= T[x]) r = *it - S[x] + 1;
}-- it;
int val = ((ll)F(y-l-1) + F(r-y-1) - F(r-l-1)) % mod;
if(val < 0) val += mod;
if(f == 0) val = mod - val,s[v].erase(it);
ans += root[v]->w;if(ans >= mod) ans -= mod;
root[v] = modify(root[v],1,n,x,val);
ans -= root[v]->w;if(ans < 0) ans += mod;
return ;
}
int main(){
rep(i,1,n){
T[i] = S[i] + x - 1;
}
rep(i,1,m){
tmp[++cnt] = c[i].z;
}sort(tmp+1,tmp+cnt+1);
cnt = unique(tmp+1,tmp+cnt+1) - tmp - 1;
root[0] = build(1,n);rep(i,1,cnt) root[i] = root[i-1];
rep(i,1,n) rep(j,S[i],T[i]){
a[j] = lower_bound(tmp+1,tmp+cnt+1,a[j]) - tmp;
insert(i,j-S[i]+1,a[j],1);
}printf("%d\n",ans);
rep(i,1,m){
x = c[i].x;y = c[i].y;v = c[i].z;
v = lower_bound(tmp+1,tmp+cnt+1,v) - tmp;
insert(x,y,a[S[x]+y-1],0);
insert(x,y,a[S[x]+y-1]=v,1);
printf("%d\n",ans);
}
return 0;
}


数学上来先打表

题目:

1. 添加一条 $x$$y$ 之间的双向边。
2. 回到第 $x$ 次操作后的状态。（注意这里的 $x$ 可以是 $0$，即回到初始状态）
3. 查询 $x$ 所在联通块能到的点中点权第 $y$ 小的值，如果不存在，那么输出 $-1$

$n,m \leq 10^5$ 时限 $2.3s$ .内存 $50MB$

题解:

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int unt;
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 100010;
struct Node{
ull s;int id,next;
void clear(){
s = 0;id = next = 0;
}
}G[maxn*6];
inline void Setit(int u,int v){
G[++cnt].s = 1ULL << (v&63);
G[cnt].id = v >> 6;
}
inline void insert(int p,Node x){
int id = top ? ws[top--] : ++ cnt;
G[id].clear();G[id] = x;
int q = G[p].next;
G[p].next = id;G[id].next = q;
}
int fa[maxn],siz[maxn],a[maxn],b[maxn],w[maxn];
inline int find(int x){
while(x != fa[x]) x = fa[x];
return x;
}
char f[65536];
int count_it(ll x){
return f[x&65535] + f[(x>>16)&65535] + f[(x>>32)&65535] + f[(x>>48)&65535];
}
inline int query(int x,int k){
x = find(x);if(k > siz[x]) return -1;
for(rg i = head[x],v;i;i = G[i].next){
v = count_it(G[i].s);
if(k > v) k -= v;
else{
rep(j,0,63) if((G[i].s >> j)&1 && (--k == 0))
return (G[i].id << 6) | j;
}
}
}
inline void Union(int x,int y){
if(x == y) return ;
fa[x] = y;siz[y] += siz[x];
if(i == 0) break;
else{
int id = top ? ws[top--] : ++ cnt;
G[id].clear();G[id] = G[i];
}i = G[i].next;
}
for(rg j = head[y],x;i;i = G[i].next){
while((x = G[j].next) && G[x].id < G[i].id) j = x;
if(x == 0) insert(j,G[i]);
else if(G[x].id == G[i].id) G[x].s |= G[i].s;
else insert(j,G[i]);
}
return ;
}
inline void split(int x,int y){
if(x == y) return ;
fa[x] = x;siz[y] -= siz[x];
if(i == 0) break;
i = G[i].next;
}else break;
}
bool flag = false;
while((x = G[j].next) && G[x].id  < G[i].id) j = x;
G[x].s ^= G[i].s;
if(G[x].s == 0){
ws[++top] = x;
G[j].next = G[x].next;
}
}
return ;
}
struct save{
int op,x,y,ans;
}zs[maxn];
vector<int> qer[maxn],lnk[maxn];
int nodecnt,pos[maxn];
void dfs(int u){
int tmp;
for(vector<int>::iterator it = qer[u].begin();it != qer[u].end();++ it)
zs[*it].ans = (tmp = query(zs[*it].x,zs[*it].y)) == -1 ? -1 : b[tmp];
for(vector<int>::iterator it = lnk[u].begin();it != lnk[u].end();++ it){
rg x = find(zs[*it].x),y = find(zs[*it].y);
if(siz[x] > siz[y]) swap(x,y);
Union(x,y);dfs(zs[*it].ans);split(x,y);
}
}
int main(){
rep(i,1,65535) f[i] = f[i>>1] + (i&1);
rep(i,1,n){
w[i] = i;fa[i] = i;siz[i] = 1;
}sort(b+1,b+n+1);
rep(i,1,n){
a[i] = w[lower_bound(b+1,b+n+1,a[i])-b] ++ ;
Setit(i,a[i]);
}
int nw = 0;
rep(i,1,m){
if(zs[i].op == 1){
lnk[nw].push_back(i);
nw = nodecnt;
}else if(zs[i].op == 2) nw = pos[zs[i].x];
else{
qer[nw].push_back(i);
}
pos[i] = nw;
}
dfs(0);
rep(i,1,m) if(zs[i].op == 3){
printf("%d\r\n",zs[i].ans);
}
return 0;
}



posted @ 2017-07-03 19:51  Sky_miner  阅读(534)  评论(0编辑  收藏  举报