题意:
给出x , y , a ,b , 求{p , q} , a <= p <= x ,b <= q <= y , p > q.
解法:
无
Code:
int x , y , a , b; vector<PII> ans; void solve(){ ans.clear(); for(int i = a ; i <=x ; ++i) for (int j = b ; j <= y ; ++j) if (i > j){ ans.PB( MP(i , j)); } printf("%d\n" , ans.size()); for (int i = 0 ; i < ans.size() ; ++i) printf("%d %d\n" , ans[i].first , ans[i].second); } int main(){ while(cin >> x >>y >> a >> b){ solve(); } }
题意:
给出n 对数字[l , r], 问是否有其中一组可以覆盖所有线段
解法:
取lmin , rmax, 然后查找
Code:
int a , b , n; vector< PII > seg; void solve(){ seg.clear(); int c , d; for (int i = 0 ; i < n ; ++i){ cin >> a >> b; if (i == 0) c = a , d = b; else checkMax(d , b) , checkMin(c , a); seg.PB( MP(a , b) ); } for (int i = 0 ; i < n ; ++i){ if (seg[i].first == c && seg[i].second == d){ printf("%d\n" , i + 1); return ; } } cout << "-1" << endl; } int main(){ while (cin >> n) solve(); }
题意:
从(x0 , y0) 点到 (x1 , y1) 点,只允许走几条线段,八个方向。问最少需要多少步。
重要条件——点数最多1e5.。。曹操曹操。。。。
解法:
裸bfs。Set判断点是否存在,map记录距离。
Code:
const int N = 2e5; set< PII > vis; map< PII , int > step; queue < PII > q; const int dir[][2] = { {-1 , -1} , { -1 , 0 } , {-1 , 1} , {0 , -1} , {0 , 1} , {1 , -1} , {1 , 0} , {1 , 1} }; PII st , ed; int n , a , b , r; void solve(){ vis.clear(); step.clear(); while (!q.empty()) q.pop(); step[st] = 0; cin >> n ; vis.insert(st); vis.insert(ed); while(n--){ cin >> r >> a >> b; for (int i = a ; i <= b ; ++i) vis.insert( MP(r , i) ); } q.push(st); while (!q.empty()){ PII go , now = q.front(); int nowstep = step[now]; q.pop(); for (int d = 0 ; d < 8 ; ++d){ go = MP(now.first + dir[d][0] , now.second + dir[d][1]); if (vis.find(go) != vis.end() && step.find(go) == step.end()){ step[go] = nowstep + 1; q.push(go); if (go == ed){ cout << nowstep + 1 << endl; return; } } } } cout << -1 << endl; 0} int main(){ while(cin >> st.first >> st.second >> ed.first >> ed.second) solve(); }
题意:
给一张无向图,如果press一个点的话,它与直接相邻的点的计数器都+1。给一个序列a要使得所有的计数器数字都不为a[i] ,每个点只可以press一次,问构造方法。
解法:
直接构造,如果当前计数器的值=a[i] 的话press这个点。因为每次加值,所以a[i]= c[i] 只可能出现一次,于是一定有解。
Code:
const int N = 100009; VI adj[N]; int a[N], c[N]; VI res; int n, m; #define v adj[u][i] void press(int u){ ++c[u]; res.PB(u); REP(i, SZ(adj[u])) if (a[v] == ++c[v]) press(v); } #undef v int main(){ #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif RD(n, m); DO(m){ int u, v; RD(u, v); adj[u].PB(v); adj[v].PB(u); } REP_1(i, n) RD(a[i]); REP_1(i, n) if (a[i] == c[i]) press(i); cout << SZ(res) << endl; REP(i, SZ(res)) OT(res[i]); }
题意:
一个1e5个元素的序列,5e4个操作:
1、 将某个区间亦或一个值
2、 求某个区间的和
解法:
简单线段树。将每个数字拆成二进制,开20棵线段树,每棵线段树记录数列的每一个二进制位的01.对于操作1,将亦或的数字拆开,如果当前位是1那么将区间01翻转,否则不管;对于操作2,枚举0~20 ,求区间1的个数,乘以1 << i 求和即可。要注意的是输出答案是long long。
Code:
#define MAXN 100001 int n,m; int a[MAXN] , ia[MAXN]; const int N = 21; struct Seg{ struct SEGTREE{ int l,r,num,op; }tree[MAXN*4]; void refresh(int root){ tree[root].num = tree[root<<1].num + tree[root<<1|1].num; } void buildsegtree(int root,int l,int r) { tree[root].l = l; tree[root].r = r; tree[root].op = -1; if(l == r) { tree[root].num = a[l]; return ; } int mid = (l+r)>>1; buildsegtree(root<<1,l,mid); buildsegtree(root<<1|1,mid+1,r); refresh(root); } void pushdown(int root) { if(tree[root].op == -1) return ; if(tree[root].l != tree[root].r) { if(tree[root].op == 2) { switch(tree[root<<1].op) { case -1: tree[root<<1].op = 2; break; case 0: tree[root<<1].op = 1; break; case 1: tree[root<<1].op = 0; break; case 2: tree[root<<1].op = -1; break; } switch(tree[root<<1|1].op) { case -1: tree[root<<1|1].op = 2; break; case 0: tree[root<<1|1].op = 1; break; case 1: tree[root<<1|1].op = 0; break; case 2: tree[root<<1|1].op = -1; break; } } else tree[root<<1].op = tree[root<<1|1].op = tree[root].op; } if(tree[root].op == 0) { tree[root].num = 0; } else if(tree[root].op == 1) { tree[root].num = tree[root].r - tree[root].l + 1; } else { tree[root].num = tree[root].r - tree[root].l + 1 - tree[root].num; } tree[root].op = -1; } int query_num(int root,int l,int r) { pushdown(root); if(tree[root].l == l && tree[root].r == r) return tree[root].num; int mid = (tree[root].l + tree[root].r)>>1; if(r <= mid) return query_num(root<<1,l,r); else if(l > mid) return query_num(root<<1|1,l,r); else return query_num(root<<1,l,mid) + query_num(root<<1|1,mid+1,r); } void update(int root,int l,int r,int op) { pushdown(root); if(tree[root].l == l && tree[root].r == r) { tree[root].op = op; return ; } int mid = (tree[root].l + tree[root].r)>>1; if(r<=mid) update(root<<1,l,r,op); else if(l > mid) update(root<<1|1,l,r,op); else { update(root<<1,l,mid,op); update(root<<1|1,mid+1,r,op); } pushdown(root<<1); pushdown(root<<1|1); refresh(root); } }Meng[N]; int MM[N]; void init(){ for (int i = 0 ; i < N ; ++i) MM[i] = 1 << i; } int main() { init(); while(cin >> n) { for(int i=1;i<=n;i++) { scanf("%d",&ia[i]); } for (int i = 0 ; i < N ; ++i){ int j = (1 << i); for (int k = 1 ; k <= n ; ++k){ if (ia[k] & j) a[k] = 1; else a[k] = 0; } Meng[i].buildsegtree(1 , 1 , n); } int op,a,b,c; cin >> m ; while(m--) { scanf("%d" , &op); if (op == 1){ scanf("%d%d" , &a , &b); long long ans = 0; for (int i = 0 ; i < N ; ++i){ long long res = MM[i]; long long ret = Meng[i].query_num(1,a,b); res *= ret; ans += res; } cout << ans << endl; } else{ scanf("%d%d%d" , &a , &b , &c); for (int i = 0 ; i < N; ++i){ if (c & MM[i]) Meng[i].update(1 , a , b , 2); } } } } return 0; }
总结:
1、 岛岛的英文太神了啊!!!-- 尼玛瞬间题目就读完了Orz
2、 对木板的信心太渣了啊,E的木板用的太不熟悉
3、 题意太隐晦本屌丝的狗眼瞎了啊。。。C的点数小于1e5完全没看见,跪。
4、 下次Div2 一定要AK= =