Codeforces Round #149 (Div. 2) 水赛解题报告

A  Heads or Tails

题意:

         给出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();
    }
}

 

B  Big Segment

题意:

         给出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();
}

 

 

C  King's Path

题意:

         从(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();
}

 

 

D  Dispute

题意:

         给一张无向图,如果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]);

}

 

E  XOR on Segment

题意:

         一个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= =

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值