JNU周练1019

CodeForces 339C

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

 

直接暴搜:

ExpandedBlockStart.gif
#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 

 单点更新的线段树

ExpandedBlockStart.gif
#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

ExpandedBlockStart.gif
#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值