刷题记录(NC16692 [NOIP2001]求先序排列,NC204382 中序序列,NC23046 华华教月月做数学)

NC16692 [NOIP2001]求先序排列

题目链接

关键点:

1、已知中序和后序遍历,首先明确中序遍历是左根右,后序为左右根,先序为根左右,那么求根可以直接从后序的最后一位来找,然后在中序里找到该根(位置为pos),那么该pos的前面就为左子树,后面就为右子树,再以此类推

2、设中序(pl,pr)后序(sl,sr)左子树为

(pl,pos-1,sl,x)x-sl = pos-1-pl     ----------   x = pos-1-pl+sl;

左子树为(pl, pos-1, sl, pos-1-pl+sl)

同理右子树

find(pos+1, pr, pos-pl+sl, sr-1);

2、且无论是在左子树还是右子树,pl和pr的相差越来越近,因此有可能pl>pr,这是不存在的,因此在最开始要判断返回

完整代码:

# include <cstdio>
# include <iostream>
using namespace std;
string zhong, hou;
void find(int lz, int rz, int lh, int zh)
{
    if (lz>rz)
        return ;
    char root = hou[zh];
    cout<<root;
    int i;
    for (i=lz; i<=rz; i++)
    {
        if (zhong[i] == root)
          break;  
    }
    find(lz, i-1, lh, i-lz+lh-1);
    find(i+1, rz, i-lz+lh, zh-1);
}
int main()
{
    cin>>zhong>>hou;
    int lz = 0, rz = zhong.size()-1, lh = 0, zh = hou.size()-1;
    find(lz, rz, lh, zh);
    return 0;
}

NC204382 中序序列

题目链接

关键点

1、一样的思路,首先先序为根左右,后序为左右根,中序为左根右,且在先序中左里又可以分成根左右,然后再继续,直到只剩下一个结点,且该结点就为左节点,那么左子树的根为先序的第二个,然后再到后序里去找这个根(pos),后序里的左又可以分成左右根左右根,那么找到了左子树的根,即找到了后序里的左子树的最后

2、先序(pl, pr), 后序(sl, sr),那么左子树 deal(pl+1, x, sl, pos) x-pl-1 = pos-sl

x = pos-sl+pl+1;

同理右子树deal (x+1, pr,  pos+1, sr-1)

同样的,还是得判断区间是否存在

完整代码

vector<int>v;
class Solution {
public:
    void deal(int pr, int pl, int sr, int sl, vector<int> &pre, vector<int> &suf)
    {
        if (pr==pl)
        {
            v.push_back(pre[pr]);
            return ;
        }
        int x = pre[pr+1];
        int pos = -1;
        for (int i=sr; i<=sl; i++)
        {
            if (suf[i]==x)
            {
                pos = i;
                break;
            }
        }
        deal(pr+1, pr+1+pos-sr, sr, pos, pre, suf);
        v.push_back(pre[pr]);
        if (sl-1>=pos+1)deal(pr+1+pos-sr+1, pl, pos+1, sl-1, pre, suf);
    }
    vector<int> solve(int n, vector<int>& pre, vector<int>& suf) {
        deal(0, pre.size()-1, 0, suf.size()-1, pre, suf);
        return v;
    }
};

NC23046 华华教月月做数学

题目链接

关键点

1、快速幂和快速乘,快速幂是将次方分成二进制数,而快速乘将一个乘数分成二进制数(看成n个m相加)

完整代码:

# include <cstdio>
# include <iostream>
using namespace std;
typedef long long ll;
int t;
ll a, b, p;
ll cheng(ll x, ll y)
{
    ll base = x%p;
    ll ans = 0;
    while (y)
    {
        if (y&1)
            ans  = (ans+base)%p;
        base = (base+base)%p;
        y>>=1;
    }
    return ans;
}
ll mi()
{
    ll ans = 1;
    ll base = a%p;
    while (b)
    {
        if (b&1)
            ans = cheng(ans, base)%p;
        base = cheng(base, base)%p;
        b>>=1;
    }
    return ans;
}
int main()
{
    scanf("%d", &t);
    while (t--)
    {
        scanf("%lld%lld%lld", &a, &b, &p);
        cout<<mi()<<endl;
    }
    
    
    
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值