牛客题解1

现在是7:53,补一下昨天没有完成的作业吧!

兔子的逆序对 (nowcoder.com)//第一题

题目描述:
兔子最近喜欢上了逆序对。
一个逆序对(i,j) 需要满足 i < j 且 ai > aj
兔子觉得只是求一个序列的逆序对个数太没有意思了。
于是兔子想到了一个更有趣的问题!
兔子可以把区间[L,R] 反转,例如序列{1,2,3,4} 反转区间[1,3] 后是{3,2,1,4}。
兔子有m次反转操作,现在兔子想知道每次反转后逆序对个数是奇数还是偶数,兔子喜欢偶数,而讨厌奇数。
请注意,每一次反转操作都会对原序列进行改变。例如序列{1,2,3,4} 第一次操作区间[1,2] 后变成{2,1,3,4} 第二次反转区间[3,4] 后变成 {2,1,4,3}

输入描述:
第一行一个整数 n,表示序列的大小。
第二行 n 个整数ai 表示序列的各个元素。
第三行一个整数m,表示操作个数。
接下来 m 行,每行两个整数 l,r,表示反转的区间。

输出描述:

输出共m行每行一个字符串,表示反转后序列逆序对个数的奇偶性,如果是逆序对个数奇数,输出"dislike"(不含引号),如果是偶数,输出"like"。

思路:树状数组求逆序对,区间翻转只是对区间内部逆序对有影响,对于区间外部的逆序对并不会产生影响,这就是突破口。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct ff
{
    int val,pos;
    bool operator<(const ff b)
    {
        return val<b.val;
    }
}a[N];
int c[N];
int n;
//主要是翻转操作,对于一个区间的翻转,区间外部的逆序对数量是不会变的,主要就是内部逆序对的数量,所以只要考虑内边逆序对数量如何变化即可
//区间内部:逆序对+顺序对=总对数
//翻转之后,逆序对-》顺序对,顺序对-》逆序对
//总对数:(r-l+1)*(r-l)/2;
//区间内部逆序对最后数量=原来逆序对总数-区间内部逆序对数量+(区间内部顺序对的数量)=翻转之后总逆序对数量
//ans-(r-l+1)*(r-l)/2-2*x;//2*x对奇偶性不会有影响
int lowbit(int u)
{
    return u&-u;
}
void add(int u)
{
    while(u<=n)
    {
        c[u]++;
        u+=lowbit(u);
    }
}
int sum(int i)
{
    int ans=0;
    while(i)
    {
        ans+=c[i];
        i-=lowbit(i);
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].val;
        a[i].pos=i;
    }
    sort(a+1,a+n+1);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        add(a[i].pos);
        ans+=i-sum(a[i].pos);
    }
    ans=ans%2;
    int mm;
    cin>>mm;
    while(mm--)
    {
        int l,r;
        cin>>l>>r;
        ans=(ans+(r-l+1)*(r-l)/2)%2;
        if(ans)    cout<<"dislike\n";
        else    cout<<"like\n";
    }
    return 0;
}

大吉大利,今晚吃鸡 (nowcoder.com)        //第二题

题目描述:

糖和抖m在玩个游戏,规定谁输了就要请谁吃顿大餐:抖m给糖a b c三个驻, 并在a柱上放置了数量为n的圆盘,圆盘的大小从上到下依次增大,现在要做的事就是把a柱的圆盘全部移到c柱,移动的过程中保持小盘在上,大盘在下,且限定圆盘只能够移动到相邻的柱子,即a柱子上的圆盘只能够移动到b,b柱子上的圆盘只能够移动到a或者c,c同理。现在请你设计一个程序,计算所需移动的最小步数, 帮助糖赢得大餐!

输入描述:

每一行输出有一个整数n(0<=n<26), 直至文件末尾。

输出描述:

对于每一组数据,输出一行,输出移动的最小步数M。

思路:汉诺塔问题。

汉诺塔问题:
相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。


我们先来对汉诺塔的步数进行一下递推。
对于n个盘子,我们可以把它分成n-1个盘子和最后一个大盘子。设F(n)为移动所需步数,那么对于n个盘子来说所做的事情就是将n-1个盘子借助C柱移动到B柱上,这一过程移动的步数为F(n-1)F,下一步我们将大盘子移动到C柱上,此时需要一步,最后,我们再将n-1n−1个盘子借助A柱移动到C柱上,此时需要的步数仍为F(n-1)。综合以上分析,F(n)=2F(n-1)+1。对两边同时加上1可以凑成一个等比数列,然后就可以求出其通项公式。

对于本题

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值