JNU周练1019

CodeForces 339C

 题意:有k(1<=k<=10)种砝码,重量范围在1~10,轮流在天平左右盘放砝码(相邻两次不能相同),要求每一轮放砝码的那一边要重于另一边,如果按这种规则能放m(m<=1000)次,则输出YES,并输出放砝码的序列,若不存在,输出NO。

直接暴搜:

#include <iostream>
#include <string>
#include <stack>
using namespace std;

int m, w[11], wn, lr[2], ans[1005];
stack<int> st;
bool dfs(int t, int pre)
{
    //cout << "dfs: " << t << endl;
    if(t>m)
    {
        return true;
    }
    int a = t % 2, b = (a + 1) % 2;

    for(int i=0; i<wn; i++)
    {
        if(pre == w[i]) continue;
        if(lr[a]+w[i]>lr[b])
        {
            lr[a] += w[i];
            st.push(w[i]);
            if(dfs(t+1, w[i])) return true;
            lr[a] -= w[i];
            st.pop();
        }
    }
    return false;
}

int main()
{
    string s;
    cin >> s >> m;
    wn = 0;
    for(int i=0; i<10; i++)
        if(s[i]=='1')
            w[wn++] = i + 1;
    lr[0] = lr[1] = 0;
    if(dfs(1,0))
    {
        cout << "YES" << endl;
        int n = st.size();
        for(int i=n; i>0; i--)
        {
            ans[i] = st.top();
            st.pop();
        }
        for(int i=1; i<=n; i++)
        {
            if(i!=1) cout << " ";
            cout << ans[i];
        }
        cout << endl;
    }
    else
        cout << "NO" << endl;
    return 0;
}
View Code 

CodeForces 339D 

 单点更新的线段树

#include <iostream>
using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1

const int MAX = 140000;
int ans[MAX<<4];

void push_up(int rt, int level)
{
    if(level==0)
        ans[rt] = ans[rt<<1] ^ ans[rt<<1|1];
    else
        ans[rt] = ans[rt<<1] | ans[rt<<1|1];
}

//level: 0-xor   1-or
void build(int l, int r, int rt, int level)
{
    if(l==r)
    {
        cin >> ans[rt];
        return ;
    }

    int m = (l + r) >> 1;
    build(lson, (level+1)%2);
    build(rson, (level+1)%2);
    push_up(rt, level);
}

void update(int p, int d, int l, int r, int rt, int level)
{
    if(l==r)
    {
        ans[rt] = d;
        return ;
    }

    int m = (l + r) >> 1;
    if(p<=m) update(p, d, lson, (level+1)%2);
    else update(p, d, rson, (level+1)%2);
    push_up(rt, level);
}

void query()
{
    cout << ans[1] << endl;
}

int main()
{
    int n, m, nn = 1, k, p, d;
    cin >> n >> m;
    for(int i=1; i<=n; i++)
        nn *= 2;
    k = n % 2;
    build(1,nn,1,k);
    for(int i=1; i<=m; i++)
    {
        cin >> p >> d;
        update(p, d, 1, nn, 1, k);
        query();
    }

    return 0;
}
View Code 

CodeForces 339E

 题意:有一个1~n的初始数列,有一种替换操作(l, r)将第l个与第r个之间数列调转。给出一个数列,求经过怎样的替换得到该数列。其中,三步以内的操作必存在。

一开始的思路是深搜,但是遇到整个数列都经历过替换的就出现问题。如:5、4、3、2、10、1、9、8、7、6

CF上的思路

We will call the command l, r a reverse, also we will call the row of horses an array. Suddenly, right?

The problem can be solved with clever bruteforcing all possible ways to reverse an array. To begin with, assume that the reverse with l = r is ok. Our solution can find an answer with such kind of reverses. It is clear that this thing doesn't affect the solution. Because such reverses can simply be erased from the answer.

The key idea: reverses split an array into no more than seven segments of the original array. In other words, imagine that the array elements was originally glued together, and each reverse cuts a segment from the array. Then the array would be cut into not more than 7 pieces.

Now you can come up with the wrong solution to the problem, and then come up with optimization that turns it into right. So, bruteforce all ways to cut array into 7 or less pieces. Then bruteforce reverse operations, but each reverse operation should contain only whole pieces. It is clear that this solution is correct, One thing it does not fit the TL.

How to improve it? Note that the previous solution requires the exact partition of the array only at the very end of the bruteforce. It needed to check whether it is possible to get the given array a. So, let's assume that the array was originally somehow divided into 7 parts (we don't know the exact partition), the parts can be empty. Now try to bruteforce reverses as in naive solution. One thing, in the very end of bruteforce try to find such a partition of the array to get (with fixed reverses) the given array a.

The search for such a partition can be done greedily (the reader has an opportunity to come up with it himself). Author's solution does this in time proportional to the number of parts, that is, 7 operations. However, this can be done for O(n) — this should fit in TL, if you write bruteforce carefully.

Ac code

#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;

int ans[7], flag;
int a[1005], n;
int pos[4][30], pn[4];
struct Pair
{
    int l, r;
}p[4][300];
int pai[4];

stack<int> s;

bool check()
{
    for(int i=1; i<=n; i++)
    {
        if(a[i]!=i)
            return false;
    }
    return true;
}

void find_pos(int index)
{
    //求特殊位置
        pn[index] = 0;
        pos[index][++pn[index]] = 1;
        for(int i=2; i<n; i++)
        {
            if( !((a[i-1]==a[i]+1&&a[i+1]==a[i]-1) || (a[i-1]==a[i]-1&&a[i+1]==a[i]+1)) )
                pos[index][++pn[index]] = i;
        }
        pos[index][++pn[index]] = n;
}

void to_pair(int index)
{
    //
    pai[index] = 0;
    for(int i=1; i<=pn[index]; i++)
    {
        for(int j=i; j<=pn[index]; j++)
        {
            p[index][++pai[index]].l = pos[index][i];
            p[index][pai[index]].r = pos[index][j];
        }
    }
}

int main()
{
    cin >> n;
    for(int i=1; i<=n; i++)
        cin >> a[i];
    find_pos(1); to_pair(1);
    for(int i=1; i<=pai[1]; i++)
    {
        reverse(a+p[1][i].l, a+p[1][i].r+1);
        find_pos(2);
        if(pn[2]>10)
        {
            reverse(a+p[1][i].l, a+p[1][i].r+1);
            continue;
        }
        s.push(p[1][i].r);
        s.push(p[1][i].l);
        to_pair(2);
        for(int j=1; j<=pai[2]; j++)
        {
            reverse(a+p[2][j].l, a+p[2][j].r+1);
            find_pos(3);
            if(pn[3]>6)
            {
                reverse(a+p[2][j].l, a+p[2][j].r+1);
                continue;
            }
            s.push(p[2][j].r);
            s.push(p[2][j].l);
            to_pair(3);
            for(int k=1; k<=pai[3]; k++)
            {
                reverse(a+p[3][k].l, a+p[3][k].r+1);
                flag = 0;
                if(check())
                {
                    flag = 1;
                    s.push(p[3][k].r);
                    s.push(p[3][k].l);
                    ans[0] = s.size() / 2;
                    ans[1] = s.top(); s.pop();
                    ans[2] = s.top(); s.pop();
                    ans[3] = s.top(); s.pop();
                    ans[4] = s.top(); s.pop();
                    ans[5] = s.top(); s.pop();
                    ans[6] = s.top(); s.pop();
                    for(int i=1; i<=5; i+=2)
                    {
                        if(ans[i]==ans[i+1])
                        {
                            ans[0]--;
                        }
                    }
                    cout << ans[0] << endl;
                    for(int i=1; i<=5; i+=2)
                    {
                        if(ans[i]!=ans[i+1])
                            cout << ans[i] << " " << ans[i+1] << endl;
                    }

                }
                if(flag) break;
                reverse(a+p[3][k].l, a+p[3][k].r+1);
            }
            if(flag) break;
            reverse(a+p[2][j].l, a+p[2][j].r+1);
            s.pop(); s.pop();
        }
        if(flag) break;
        reverse(a+p[1][i].l, a+p[1][i].r+1);
        s.pop(); s.pop();
    }
}
View Code 
原文地址:https://www.cnblogs.com/byluoluo/p/3379273.html