noi 2017 简要题解
回顾noi 2017
DAY1
整数
压位维护序列。用线段树维护一段0后第一个1,一段A-1后第一个<(A - 1)的数
推推转移式子即可
代码犯了无数个错误,并且检查的时候没有仔细的检查出来,仍然借助gdb和对拍才调出来!非常糟糕!
**1. 线段树初始化错误
**2. 打错变量名3处
3. 进位后写成减M,应该是M+1
4. 很多地方一开始想清楚,改的时候没有想清楚,反而改错。比如二分是找最低位非满或非0.修改的时候一定要想清楚,很多时候找到错误反而没有全面的修改,浪费了更多时间
写代码前细节在头脑中不清晰,代码写得太少了!
#include<bits/stdc++.h>
using namespace std;
#define maxn 1002020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define inf 0x3f3f3f3f
typedef long long ll;
typedef pair<int,int> pr;const ll M = (1 << 30) - 1,K = 30;
int cov[maxn << 2],tag[maxn << 2],val[maxn << 2];
// 1 : 全为M
// 2 :全为 0
// 0 :无性质
int n,t1,t2,t3,L;void build(int x,int l,int r){tag[x] = 2 , cov[x] = -1;if ( l == r ) return;int mid = (l + r) >> 1;build(x << 1,l,mid) , build((x << 1) | 1,mid + 1,r);
}
inline void cover(int x,int d){cov[x] = d , val[x] = d;if ( d == M ) tag[x] = 1;else tag[x] = 2;
}
inline void pushdown(int x){int ls = x << 1,rs = (x << 1) | 1;if ( cov[x] != -1 ){cover(ls,cov[x]);cover(rs,cov[x]);cov[x] = -1;}
}
inline void update(int x){int ls = x << 1,rs = (x << 1) | 1;if ( tag[ls] == 1 && tag[rs] == 1 ) tag[x] = 1;else if ( tag[ls] == 2 && tag[rs] == 2 ) tag[x] = 2;else tag[x] = 0;
}
void modify(int x,int l,int r,int L,int R,int d){if ( L > R ) return;if ( L <= l && R >= r ){cover(x,d);return;}int ls = x << 1,rs = (x << 1) | 1,mid = (l + r) >> 1;pushdown(x);if ( L <= mid ) modify(ls,l,mid,L,R,d);if ( R > mid ) modify(rs,mid + 1,r,L,R,d);update(x);
}
void modify(int x,int l,int r,int id,int d){if ( l == r ){val[x] += d;if ( val[x] == M ) tag[x] = 1;else if ( val[x] == 0 ) tag[x] = 2;else tag[x] = 0;return;}int ls = x << 1,rs = (x << 1) | 1,mid = (l + r) >> 1;pushdown(x);if ( id <= mid ) modify(ls,l,mid,id,d);else modify(rs,mid + 1,r,id,d);update(x);
}
int find1(int x,int l,int r,int L,int R){if ( tag[x] == 2 ) return 0;if ( l == r ) return l;int ls = x << 1,rs = (x << 1) | 1,mid = (l + r) >> 1;pushdown(x);if ( L <= l && R >= r ){if ( tag[ls] == 2 ) return find1(rs,mid + 1,r,L,R);return find1(ls,l,mid,L,R);}int p = 0;if ( L <= mid ) p = find1(ls,l,mid,L,R);if ( p ) return p;return find1(rs,mid + 1,r,L,R);
}
int find0(int x,int l,int r,int L,int R){if ( tag[x] == 1 ) return 0;if ( l == r ) return l;int ls = x << 1,rs = (x << 1) | 1,mid = (l + r) >> 1;pushdown(x);if ( L <= l && R >= r ){if ( tag[ls] == 1 ) return find0(rs,mid + 1,r,L,R);return find0(ls,l,mid,L,R);}int p = 0;if ( L <= mid ) p = find0(ls,l,mid,L,R);if ( p ) return p;return find0(rs,mid + 1,r,L,R);
}
int query(int x,int l,int r,int id){if ( l == r ) return val[x];int ls = x << 1,rs = (x << 1) | 1,mid = (l + r) >> 1;pushdown(x);if ( id <= mid ) return query(ls,l,mid,id);return query(rs,mid + 1,r,id);
}
int main(){
// freopen("input.txt","r",stdin);scanf("%d %d %d %d",&n,&t1,&t2,&t3);L = n + 1000;build(1,0,L);while ( n-- ){int t,a,b,k;scanf("%d",&t);if ( t == 1 ){scanf("%d %d",&a,&b);if ( a < 0 ){a = -a;int x = b / K,y = b % K,t = 0,vx = query(1,0,L,x),vy,delta;ll cur = (ll)a << y;delta = cur & M;if ( vx < delta ) delta -= M + 1 , t++;if ( t || cur >> K ){vy = query(1,0,L,x + 1);int delta2 = t + (cur >> K);if ( vy < delta2 ){int p = find1(1,0,L,x + 2,L);modify(1,0,L,x + 2,p - 1,M);modify(1,0,L,p,-1);delta2 -= M + 1;}modify(1,0,L,x + 1,-delta2);}modify(1,0,L,x,-delta);}else{int x = b / K,y = b % K,t = 0,vx = query(1,0,L,x),vy,delta;ll cur = (ll)a << y;delta = cur & M;if ( vx + delta > M ) delta -= M + 1 , t++;if ( t || cur >> K ){vy = query(1,0,L,x + 1);int delta2 = t + (cur >> K);if ( vy + delta2 > M ){int p = find0(1,0,L,x + 2,L);modify(1,0,L,x + 2,p - 1,0);modify(1,0,L,p,1);delta2 -= M + 1;}modify(1,0,L,x + 1,delta2);}modify(1,0,L,x,delta);}}else{scanf("%d",&a);int x = a / K;int d = query(1,0,L,x);printf("%d\n",(d >> (a % K)) & 1);}}
}
蚯蚓排队
维护hash值,map到1023333的hash表里。
每次分裂只会有k2个串被删掉,合并又至多多出k2个。
O(nk+k^2 * c)
用了两种hash表,还是过不了uoj的extra test,好像还要读入优化,不想卡常了
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x) for(register int i = head[x] ; i ; i = e[i].next)
#define pb push_back
#define prev prev_
#define stack stack_
#define inf 0x3f3f3f3f
#define maxn 200020
#define N 10000020
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pr;struct hashmap
{int head[10233333] , len[20000010] , cnt[20000010] , next[20000010] , tot;ull val[20000010];inline void insert(int l , ull v){int x = v % 10233333 , i , last = 0;for(i = head[x] ; i ; last = i , i = next[i])if(len[i] == l && val[i] == v)break;if(i) cnt[i] ++ ;else{if(!last) head[x] = ++tot;else next[last] = ++tot;len[tot] = l , val[tot] = v , cnt[tot] ++ ;}}inline void erase(int l , ull v){int x = v % 10233333 , i;for(i = head[x] ; i ; i = next[i])if(len[i] == l && val[i] == v)cnt[i] -- ;}inline int find(int l , ull v){int x = v % 10233333 , i;for(i = head[x] ; i ; i = next[i])if(len[i] == l && val[i] == v)return cnt[i];return 0;}
}rec;
const int MAXK = 50;
const int MAXN = 200005;
const int MAXL = 1e7 + 5;
const int MAXS = 2e7 + 5;
const int HASH = 1e7 + 19;
struct HashTable {int tot, head[HASH];int val[MAXS], nxt[MAXS];ull mask[MAXS];void insert(ull msk, int value) {int p = head[msk % HASH];while (p != 0) {if (mask[p] == msk) {val[p] += value;return;}p = nxt[p];}tot++;mask[tot] = msk;val[tot] = value;nxt[tot] = head[msk % HASH];head[msk % HASH] = tot;}int query(ull msk) {int p = head[msk % HASH];while (p != 0) {if (mask[p] == msk) return val[p];p = nxt[p];}return 0;}
} HT;
const ull base = 97;
const ll mod = 998244353;
int n,m,a[maxn],pre[maxn],post[maxn];
char ch[maxn];
ull pow_[maxn];void init(){pow_[0] = 1;rep(i,1,100) pow_[i] = pow_[i - 1] * base;
}
void merge(int x,int y){int t = 1,id = x; ull cur = 0;while ( t <= 49 ){cur += pow_[t - 1] * a[id];int id2 = y; ull cur2 = cur;rep(j,1,50 - t){cur2 = cur2 * base + a[id2];// rec.insert(t + j,cur2);HT.insert(cur2,1);id2 = post[id2];if ( !id2 ) break;}id = pre[id] , ++t;if ( !id ) break;}post[x] = y , pre[y] = x;
}
void split(int x){int t = 1,id = x; ull cur = 0;while ( t <= 49 ){cur += pow_[t - 1] * a[id];int id2 = post[x]; ull cur2 = cur;rep(j,1,50 - t){cur2 = cur2 * base + a[id2];// rec.erase(t + j,cur2);HT.insert(cur2,-1);id2 = post[id2];if ( !id2 ) break;}id = pre[id] , ++t;if ( !id ) break;} pre[post[x]] = 0 , post[x] = 0;
}
int main(){init();scanf("%d %d",&n,&m);rep(i,1,n){scanf("%d",&a[i]);// rec.insert(1,a[i]);HT.insert(a[i],1);}rep(i,1,m){int t,x,y,k;scanf("%d",&t);if ( t == 1 ){scanf("%d %d",&x,&y);merge(x,y);}else if ( t == 2 ){scanf("%d",&x);split(x);}else{scanf("%s%d",ch + 1,&k);int l = strlen(ch + 1); ull cur = 0; ll ans = 1;rep(i,1,l){cur = cur * base + (ch[i] - '0');if ( i >= k ){// ans = ans * rec.find(k,cur) % mod;ans = ans * HT.query(cur) % mod;cur -= pow_[k - 1] * (ch[i - k + 1] - '0');}}printf("%lld\n",ans);}}
}
泳池
直接用大佬的吧
感觉dp还有一种推法,从左往右dp,但是方程没有这么清晰
常系数递推可以用特征多项式优化
DAY2
游戏
枚举x是a还是b型,转换成2-SAT
学到了2-SAT新姿势,输出方案直接比较tarjian后强连通分量的标号,因为标号自然构成逆拓扑序,选标号较小的即可
2-SAT连边的时候,若x1 必须选 y2 ,则 y1 必须选 x2,不能漏连,还要判是否是对同一张图的限制
不要卡常了!平时做题卡常没有意义,把时间花在想和写更多题
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x) for(register int i = head[x] ; i ; i = e[i].next)
#define pb push_back
#define prev prev_
#define stack stack_
#define inf 0x3f3f3f3f
#define maxn 200020
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pr;struct node{int next,to;
}e[maxn * 2],e2[maxn * 2];
struct node2{int x,y;int ax,ay;
}dt[maxn];int head[maxn],cnt,head2[maxn];
int dfn[maxn],ins[maxn],belong[maxn],sz[maxn],low[maxn],st[maxn],tops,dfstime;
int n,m,k,tot,id[maxn],del[maxn],flag;
char ch[maxn],ans[maxn];
pr cur[maxn];inline void adde(int x,int y){if ( x == y ) return;e[++cnt].to = y;e[cnt].next = head[x];head[x] = cnt;
}
void dfs(int x){dfn[x] = low[x] = ++dfstime;ins[x] = 1 , st[++tops] = x;fore(i,x){if ( !dfn[e[i].to] ) dfs(e[i].to) , low[x] = min(low[x],low[e[i].to]);else if ( ins[e[i].to] ) low[x] = min(low[x],low[e[i].to]);}if ( low[x] == dfn[x] ){int y = st[tops--]; ++tot;while ( y != x ){belong[y] = tot , ins[y] = 0;y = st[tops--];}belong[x] = tot , ins[x] = 0;}
}
void init(){rep(i,1,n){if ( ch[i] == 'a' ) del[i] = 1 , cur[i] = mp(i + n,i + n * 2);else if ( ch[i] == 'b' ) del[i + n] = 1 , cur[i] = mp(i,i + n * 2);else if ( ch[i] == 'c' ) del[i + n * 2] = 1 , cur[i] = mp(i + n,i);;}
}
void build(){cnt = tot = dfstime = 0;rep(i,1,n * 3) dfn[i] = low[i] = belong[i] = head[i] = 0;rep(x,1,k){int i = id[x];del[i] = del[i + n] = del[i + n * 2] = 0;if ( ch[i] == 'a' ) del[i] = 1 , cur[i] = mp(i + n,i + n * 2);else if ( ch[i] == 'b' ) del[i + n] = 1 , cur[i] = mp(i,i + n * 2);else if ( ch[i] == 'c' ) del[i + n * 2] = 1 , cur[i] = mp(i + n,i);;}rep(i,1,m){int x = dt[i].x,y = dt[i].y, ax = dt[i].ax , ay = dt[i].ay;if ( del[ax] ) continue;if ( del[ay] ){// rep(i,0,2) if ( !del[i * n + x] && i * n + x != ax ) adde(ax,i * n + x);adde(ax,cur[x].fi) , adde(ax,cur[x].se);}else{adde(ax,ay);if ( x != y ){// rep(i,0,2) if ( !del[i * n + x] && i * n + x != ax ) // rep(j,0,2) if ( !del[j * n + y] && j * n + y != ay ) // adde(j * n + y,i * n + x);if ( ax == cur[x].fi ) {if ( ay == cur[y].fi ) adde(cur[y].se,cur[x].se);else adde(cur[y].fi,cur[x].se);} else{ if ( ay == cur[y].fi ) adde(cur[y].se,cur[x].fi);else adde(cur[y].fi,cur[x].fi);} }}}
}
bool check(){build();rep(i,1,n * 3) if ( !del[i] && !dfn[i] ) dfs(i);rep(i,1,n){if ( ch[i] == 'a' ){if ( belong[i + n] == belong[i + n * 2] ) return 0;if ( belong[i + n] < belong[i + n * 2] ){ans[i] = 'B';}else ans[i] = 'C';}else if ( ch[i] == 'b' ){if ( belong[i] == belong[i + n * 2] ) return 0;if ( belong[i] < belong[i + n * 2] ){ans[i] = 'A';}else ans[i] = 'C';}else{if ( belong[i + n] == belong[i] ) return 0;if ( belong[i + n] < belong[i] ){ans[i] = 'B';}else ans[i] = 'A';}}return 1;
}
void dfs_x(int x){if ( x == k + 1 ){if ( check() ) flag = 1;return;}ch[id[x]] = 'a';dfs_x(x + 1);if ( flag ) return;ch[id[x]] = 'b';dfs_x(x + 1);
}
int main(){scanf("%d %d",&n,&k);scanf("%s",ch + 1);int cur = 0;rep(i,1,n) if ( ch[i] == 'x' ) id[++cur] = i;scanf("%d",&m);rep(i,1,m){int x,y; char ax[10],ay[10];scanf("%d%s%d%s",&x,ax,&y,ay);dt[i] = (node2){x,y,(ax[0] - 'A') * n + x,(ay[0] - 'A') * n + y};}init();dfs_x(1);if ( !flag ) puts("-1");else{rep(i,1,n) printf("%c",ans[i]);puts("");}
}
蔬菜
这篇博客说得很好
最后可以用并查集维护。
把总量拆成c份,每天的增量是当天坏掉的,这个思路很巧。可以这么拆是因为题目中每天坏掉的是固定的那几个,而卖出后就不会坏了。
读题要看样例解释!!
一开始想错了,以为大的一定先选
不知道为什么一定要倒过来求所有的答案,感觉正着每次选最大的m个也是一样的
update: 正着做的确可以。其实原理一样
打错了变量,并查集在x = 0时特判少了,检查代码仍然没有读出来,又借助对拍,非常糟糕!
静下来读代码!!
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x) for(register int i = head[x] ; i ; i = e[i].next)
#define pb push_back
#define prev prev_
#define stack stack_
#define inf 0x3f3f3f3f
#define maxn 200020
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pr;struct node{int a,c,tp,t,x;bool operator < (node cur)const{return a < cur.a;}
};
priority_queue <node> heap;
int n,m,mx,q,p[maxn];
int last[maxn];
int g[maxn * 10],cnt,num[maxn];
ll ans[maxn];
int getlast(int x){if ( x > mx ) return getlast(mx);return x == last[x] ? x : last[x] = getlast(last[x]);
}
int main(){scanf("%d %d %d",&n,&m,&q);rep(i,1,n){int a,x,s,c;scanf("%d %d %d %d",&a,&s,&c,&x);heap.push((node){a + s,1,1,x ? (c - 1) / x + 1 : 100000,x});if ( c > 1 ) heap.push((node){a,c - 1,0,x ? (c - 2) / x + 1 : 100000,x});}rep(i,1,q) scanf("%d",&p[i]) , mx = max(mx,p[i]);rep(i,1,mx) last[i] = i , num[i] = m;while ( heap.size() ){node cur = heap.top(); heap.pop();int a = cur.a , c = cur.c , tp = cur.tp , t = cur.t , x = cur.x , p = 0 , np;if ( tp ){p = getlast(t);if ( p ){g[++cnt] = a;num[p]--;if ( !num[p] ) last[p] = getlast(p - 1);}}else{if ( !x ) p = mx;else p = t , c -= (p - 1) * x;np = getlast(p) , c += (p - np) * x , p = np;while ( p ){if ( !c ) break;int delta = min(num[p],c);rep(i,1,delta) g[++cnt] = a;c -= delta , num[p] -= delta;if ( !num[p] ) last[p] = getlast(p - 1);np = getlast(p - 1) , c += (p - np) * x , p = np;}}}ll sum = 0;rep(i,1,cnt){sum += g[i];ans[(int)ceil((double)i / m)] = sum;}rep(i,1,mx) ans[i] = max(ans[i],ans[i - 1]);rep(i,1,q) printf("%lld\n",ans[p[i]]);
}
分身术
暂时留坑
代码更新中
总结
想题要给自己定时,找性质再确认结论,要把式子推清楚
如果不推清楚式子,只是大概是这样,想了没有任何意义。必须踏踏实实把式子推完整,把细节想清楚!
noi 2017 简要题解相关推荐
- NOI 2018 简要题解
D1T1 洛谷题目传送门 题目描述 给定一个n个点m条边的无向图,每条边有高度和长度,Q次询问,每次给定起点,以及限制高度,求从起点能通过高度大于限制高度的边到达的点中,到1号点最短路的最小值 强制在 ...
- Noip 2014酱油记+简要题解
好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...
- c语言1106回文数,Codeforces 1106 简要题解
A题 传送门 读错题还能过样例我给自己点个赞. 题意简述:给一个010101网格SSS,问满足Si,j=Si+1,j+1=Si+1,j−1=Si−1,j−1=Si−1,j+1S_{i,j}=S_{i+ ...
- 湖南省第十届蓝狐网络杯大学生计算机程序设计竞赛,2019年湖南省大学生计算机程序设计竞赛 (HNCPC2019) 简要题解...
2019年湖南省大学生计算机程序设计竞赛 (HNCPC2019) 简要题解 update10.01 突然发现叉姐把这场的题传到牛客上了,现在大家可以有地方提交了呢. 不知道该干什么所以就来水一篇题解 ...
- 杂题记录及简要题解(一)
一些前几天做过的还不错的但是不是太想专门花一整篇博客的篇幅去写的题就简要地记录在这里. 说是简要题解,其实写得还是挺详细的.之后的杂题记录可能就会写得简略一点. CF1060E Sergey and ...
- BJOI2018简要题解
BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...
- SCOI2016 Day2 简要题解
「SCOI2016」妖怪 题意 有 \(n\) 只妖怪,每只妖怪有攻击力 \(\text{atk}\) 和防御力 \(\text{dnf}\) ,在环境 \((a, b)\) 下,它可以把攻击力和防御 ...
- ACC026简要题解
这场AGC是时间正好在NOI之前休养生息的日子里,果断选择了放弃(虽然也从没有用大号打过).在随便做完了前几题之后就踏上了去长沙的旅程.NOI系列比赛总是休闲无比,咕咕不断,竟然连开幕式都能咕,今天A ...
- 【NOI2019十二省联合省选】部分题简要题解
Day 1 T1 异或粽子 题意:给出一个长为n的序列,选择K个不完全重合的区间使得每个区间的异或值的总和最大. 题解:先做一个前缀异或和,对于每一个右端点我们记录三元组(l,r,x)表示在左端点在\ ...
最新文章
- Django视图之状态保持
- 窗口管理器 实现_「42」Python布局管理器(三):place实现组件的精确与灵活布局...
- TensorFlow升级1.4:Cannot remove entries from nonexistent file \lib\site-pack
- K8S Learning(8)—— Service
- 采用JAVASCRIPT实现全选的三种情况
- 【注意力机制】CBAM详解
- 使用share prefernces实现轻量级数据存储
- C#音视频处理开源项目收录
- android wear系统源码,android wear5.1怎么样 android wear5.1更新评测
- 两个三维图像互信息python_两的解释|两的意思|汉典“两”字的基本解释
- 如何烧录程序_鸿蒙实战课堂 | 如何完成一次HarmonyOS操作系统移植?
- IIS6.0PUT漏洞复现
- firefox 2.0版如何自己制作绿色版?
- 中国余数定理解题步骤
- python:panda
- 聚观早报 | 百度文心一言被用户挤爆;贝莱德准备竞购瑞信
- 微信小程序通过code去获取微信用户的加密信息
- 计算机房灭火器单具基准,厂房、车间灭火器配置计算范例
- 硬件辅助虚拟化 之EPT(内存虚拟化)介绍
- 【笔记】Python开发工程师要求摘录