Codeforces Round #430 (Div. 2) A B 水 C dfs,思维 D trie,二进制
Codeforces Round #430 (Div. 2)
A 全场hack题,,有个坑,直接判 l~r 是否在 x*k ~ y*k 之间就挂了,因为并不是 x*k~y*k 之间所有数都可以。如:7,7,3,6,2 。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 200005; ll l, r, x, y, k; int main() { scanf("%lld%lld%lld%lld%lld", &l, &r, &x, &y, &k); for(ll i = x; i<=y; ++i) { ll c = i*k; if(l<=c && c<=r) return 0*printf("YES"); } puts("NO"); return 0; }
B 水
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 200005; const double eps = 1e-6; double dis(double x1, double y1, double x2, double y2) { return sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) ); } int n, ans; double r, d, xi, yi, ri; bool check(double x, double y, double r2) { double a1 = dis(x, y, 0, 0) + ri; double a2 = dis(x, y, 0, 0) - ri; if( a2>=(r-d) && r>=a1) return true; else return false; } int main() { scanf("%lf%lf", &r, &d); scanf("%d", &n); rep(i,1,n) { scanf("%lf%lf%lf", &xi, &yi, &ri); if(check(xi, yi, ri)) ++ans; } printf("%d\n", ans); return 0; }
C dfs
题意:一棵树,对于每个点 x ,可以删去从根节点 1 到 x 这条链上的一个点,或者不删,然后问这条链上所有数的gcd最大可以是多少。
tags:
考虑 dfs 搜到节点 u 时,设 fa 是 u 的父亲节点,我们有三种选择:
1】选下这个数a[u],且点1到点 fa 之间的所有点都选上。
2】不选这个数a[u],且点1到点 fa 之间的所有点都选上。
3】选下这个数,且点1到点 fa 之间删去一个点。
用一个集合set[u] 存下点1到点 fa 之间删去一个点可能得到的所有gcd,然后在搜索时根据set[fa]更新set[u]即可。
因为要求的是gcd,会有很多重复的数,所以se[u]是不会增长很快的。
// CF C #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 200005; int n, a[N], x, y, ans[N]; vector<int > G[N]; set<int > se[N]; void Init() { rep(i,0,N-1) G[i].clear(), se[i].clear(); mes(ans, 0); } void dfs(int u, int fa, int now) { ans[u] = max(ans[u], now); se[u].insert(now); for(auto v : se[fa]) { int g = __gcd(v, a[u]); se[u].insert(g); ans[u] = max(ans[u], g); } now = __gcd(now, a[u]); ans[u] = max(ans[u], now); for(auto v : G[u]) if(v!=fa) { dfs(v, u, now); } } int main() { scanf("%d", &n); Init(); rep(i,1,n) scanf("%d", &a[i]); rep(i,1,n-1) { scanf("%d%d", &x, &y); G[x].PB(y); G[y].PB(x); } dfs(1, 0, 0); rep(i,1,n) printf("%d ", ans[i]); puts(""); return 0; }
D trie
题意:有 n 个数 ai,m个询问,每次询问有一个 x,表示这 n 个数都变为 ai^x,然后求异或后的 mex。
tags:第一次做这种题,才知道可以用字典树。。
首先要想到 m 次询问可以累积,即第一次异或 x1,第二次异或 x2,那第二次就可以直接求序列异或上 (x1^x2) 的答案。这样就不需要每次更新序列。
然后就是要怎么求这个序列异或上一个值后的 mex ?
摘自大神博客:很多二进制关于异或求最值的问题,都可以转换为字典树来求,然后在字典树上往最左边或者最右边跑,使得结果达到最值。
对于这个题,假如我们要异或上 x ,那把序列中的数按二进制位建好字典树后,把 x 按二进制位从字典树根节点往下走,在每一层尽量往小的那一边走。
如走到第 i 层时,x 二进制位是 0,那我们就看 0 结点子树是否满了,没满就往 0 子树走,满了就往 1 子树走; 反之如第 i 层时 x 二进制位是 1,异或一下则表示这一层要反一下,即看 1 子树是否满了。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 300005; struct trie { int cnt; bool is; trie *child[2]; trie() { mes(child, NULL); cnt = 0, is = false; } }; trie *root = new trie, *current; void Insert(char *str) { current = root; rep(i,0,19) { int j = str[i] - '0'; if(current->child[j]==NULL) current->child[j] = new trie; current = current->child[j]; ++current->cnt; if(current->cnt == 1<<(19-i)) current->is = true; } } int Serch(char *str) { int ans = 0; current = root; rep(i,0,19) { int j = str[i] - '0'; ans <<= 1; if(j==0) { rep(l,0,1) if(current->child[l]==NULL) current->child[l] = new trie; if(current->child[0]->is) current = current->child[1], ans++; else current = current->child[0]; } else { rep(l,0,1) if(current->child[l]==NULL) current->child[l] = new trie; if(current->child[1]->is) current = current->child[0], ans++; else current = current->child[1]; } } return ans; } int n, m, ai, x; bool vis[N]; char str[30]; void getstr(int y) { per(i,19,0) { int y2 = 1<<i; if(y2<=y) y-=y2, str[19-i]='1'; else str[19-i]='0'; } } int main() { scanf("%d%d", &n, &m); rep(i,1,n) { scanf("%d", &ai); if(vis[ai]==0) { getstr(ai); Insert(str); } vis[ai] = 1; } int s = 0; rep(i,1,m) { scanf("%d", &x); s ^= x; getstr(s); printf("%d\n", Serch(str)); } return 0; }