codeforces round 430 div 2

A:略坑 枚举l-r,看是否能整除k且商的范围是不是在x,y里

#include<bits/stdc++.h>
using namespace std;
int l, r, x, y, k;
int main()
{
    cin >> l >> r >> x >> y >> k;
    for(int i = l; i <= r; ++i) if(i % k == 0)
    {
        int t = i / k;
        if(t >= x &&t <=y )
        {
            puts("YES");
            return 0;
        }
    } 
    puts("NO");
    return 0;
}
View Code

B:判断一下就行了

#include<bits/stdc++.h>
using namespace std;
double r, d;
int n, ans;
double dis(double x, double y)
{
    return sqrt(x * x + y * y);
}
int main()
{
    cin >> r >> d >> n;
    for(int i = 1; i <= n; ++i) 
    {
        double x, y, R;
        scanf("%lf%lf%lf", &x, &y, &R);
        double dist = dis(x, y);
        if(dist - R >= r - d && dist + R <= r) ++ ans;
    }
    printf("%d\n", ans);
    return 0;
} 
View Code

C:和一道poi的题有同样的性质,可是那道题我忘了。。。
其实我们发现,每次如果一个数和另一个数的gcd,要么不变,要么至少除以2,所以我们每个节点开个set,保存把一个节点赋0的所有gcd和没有赋过0的gcd,这样其实每个节点能够得到的gcd只有log个,然后我们暴力把自己父亲节点的gcd和这个节点的数做一个gcd,相当于这个节点的值取0,然后一直dfs,最后输出每个节点的set里的最大值

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<iostream>
using namespace std;
const int N = 200010;
struct edge {
    int nxt, to;
} e[N << 1];
int n, cnt = 1;
int head[N], a[N];
set<int> s[N];
void link(int u, int v)
{
    e[++cnt].nxt = head[u];
    head[u] = cnt;
    e[cnt].to = v;
}
void dfs(int u, int last, int g)
{ 
    s[u].insert(g); // 这个点为0 
//    s[u].insert(__gcd(g, a[u]));
    for(set<int> :: iterator it = s[last].begin(); it != s[last].end(); ++it) s[u].insert(__gcd(a[u], *it));
    for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last) dfs(e[i].to, u, __gcd(g, a[u])); 
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for(int i = 1; i < n; ++i)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        link(u, v);
        link(v, u);
    }
    s[0].insert(0);
    dfs(1, 0, 0);
    for(int i = 1; i <= n; ++i) printf("%d ", *(s[i].rbegin()));
    return 0;
}
View Code

D:比赛时没用trie树各种调不出来。。。看来我对trie树的理解不够深刻。。。
我们可以想到,我们把每个数插入trie树,然后我们维护每个节点的子树是否满了,然后贪心,如果这位为0的子树没满,那么自然向为0的子树走,否则只能向为1的子树走,每次异或一个数我们就在trie树上打标记,像普通splay一样就行了 注意每次要把标记传给两个儿子,不仅仅是交换两个儿子

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
int n, m, last, cnt = 1;
int vis[N];
struct Trie {
    struct node {
        int full, ch[2], rev;
    } t[N * 10];
    void pushdown(int x, int bit)
    {
        if(!t[x].rev) return;
        t[t[x].ch[0]].rev ^= t[x].rev;
        t[t[x].ch[1]].rev ^= t[x].rev;
        if(t[x].rev & (1 << bit)) swap(t[x].ch[0], t[x].ch[1]);
        t[x].rev = 0;
    }
    void insert(int x, int num, int bit)
    {
        if(bit == -1) { t[x].full = 1; return; }
        int b = (num & (1 << bit)) > 0;
        if(t[x].ch[b] == 0) t[x].ch[b] = ++cnt;
        insert(t[x].ch[b], num, bit - 1);
        t[x].full = t[t[x].ch[0]].full & t[t[x].ch[1]].full;
    }
    int query(int x, int num, int bit)
    {
        if(bit == -1) return 0;
        pushdown(x, bit);
        if(t[t[x].ch[0]].full) return query(t[x].ch[1], num, bit - 1) + (1 << bit);
        else return query(t[x].ch[0], num, bit - 1);
    }
} trie;
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) 
    {
        int x;
        scanf("%d", &x);    
        if(vis[x] == 0)
        {
            vis[x] = 1;
            trie.insert(1, x, 20);
        }
    }
    while(m --)
    {
        int x;
        scanf("%d", &x);
        trie.t[1].rev ^= x;
        printf("%d\n", trie.query(1, last, 20));
    }
    return 0;
}
View Code

这次cf的题目挺不错的,但是由于自己傻逼trie树写不对滚粗了。。。

 

posted @ 2017-09-01 13:53  19992147  阅读(125)  评论(0编辑  收藏  举报