作业题解 [2024/6/1]

题目①P1044 [NOIP2003 普及组] 栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解:计算栈能形成的序列种数

从第一个数到最后一个数有明显的最优子结构和递推关系,考虑动态规划

设dp[i][j]表示考虑到第i个数字,栈内有j个元素的顺序数,依次考虑第1-n个数字。然后对每个数字有两种情况,入栈后要么留在栈顶,要么弹出去形成顺序,遂写出以下转移

    for(int i=2;i<=n;i++)
    for(int j=0;j<i;j++)
    for(int s=j;s>=0;s--)
    {
        if(s==0)dp[i][s]+=dp[i-1][j];//注意这里是为了不与后面重复
        dp[i][s+1]+=dp[i-1][j];
    }

最后注意初始化

dp[1][1]=1,dp[1][0]=1;

即可

题目②P1228 地毯填补问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解:将当前图形分成一二三四象限,空地在的象限对其他象限一定会少一个地毯,而将当前地毯放在最中心处恰好满足这个条件,即地毯残缺的象限在空地所在的象限,然后继续分别单独处理四个象限。注意上述其他三个象限,因为地毯放了之后会有一个地方不能占,这个地方可以视为空地处理,代码略长(难看)。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int mx=2e5+3;
typedef struct{int li,ls;}pos;
inline int getpos(pos st,int d,pos target)
{
    if(target.li-st.li>=d/2)
    {
        if(target.ls-st.ls>=d/2)return 4;
        else return 3;
        //下面
    }else{
        if(target.ls-st.ls>=d/2)return 1;
        else return 2;
    }
    //返回象限
}
inline void ser(pos st,int d,pos target)
{
    if(d<2)return;
    int pi=getpos(st,d,target);
    pos newst[5],ntg[5];
    newst[1].li=st.li,newst[1].ls=st.ls+d/2;
    newst[2].li=st.li,newst[2].ls=st.ls;
    newst[3].li=st.li+d/2,newst[3].ls=st.ls;
    newst[4].li=st.li+d/2,newst[4].ls=st.ls+d/2;

    ntg[1].li=st.li+d/2-1,ntg[1].ls=st.ls+d/2;
    ntg[2].li=st.li+d/2-1,ntg[2].ls=st.ls+d/2-1;
    ntg[3].li=st.li+d/2,ntg[3].ls=st.ls+d/2-1;
    ntg[4].li=st.li+d/2,ntg[4].ls=st.ls+d/2;

    ntg[pi].li=target.li,ntg[pi].ls=target.ls;

    if(pi==1)cout<<st.li+d/2<<" "<<st.ls+d/2-1<<" "<<2<<"\n";
    if(pi==2)cout<<st.li+d/2<<" "<<st.ls+d/2<<" "<<1<<"\n";
    if(pi==3)cout<<st.li+d/2-1<<" "<<st.ls+d/2<<" "<<3<<"\n";
    if(pi==4)cout<<st.li+d/2-1<<" "<<st.ls+d/2-1<<" "<<4<<"\n";

    ser(newst[1],d/2,ntg[1]);
    ser(newst[2],d/2,ntg[2]);
    ser(newst[3],d/2,ntg[3]);
    ser(newst[4],d/2,ntg[4]);
}
inline void solve()
{
    int k,n,m;
    cin>>k>>n>>m;
    pos st,tg;
    st.li=1,st.ls=1;
    tg.li=n,tg.ls=m;

    int d=1;
    for(int i=1;i<=k;i++)d*=2;

    ser(st,d,tg);
}
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	solve();
	return 0;
}

题目③Problem - B - Codeforces

解:(最近太懒,原谅我把昨天的cf拿来用)对i位置,m秒后的答案就是区间[max(i-m,0),i+m]的区间连或。因为考虑其他数的话,对i的贡献是逐秒靠近的,m秒能靠近多少数,i就能或到几个数,所以计算一下区间或即可,

inline void solve()
{
    ll n,m,k;
    cin>>n>>m;
    k=m;
    ll d=(n-k>=0)?n-k:0,u=n+k;
 
    auto calc=[&](ll mi,ll mx)->ll{
        int p=-1;
        for(int i=31;i>=0;i--)
        {
            ll t=1<<i;
            if((mi&t)!=(mx&t)){
                p=i;
                break;
            }
        }
        for(int i=p;i>=0;i--)mx=(mx|(1<<i));
        return mx;
    };//算区间[mi,mx]或结果
 
    cout<<(calc(min(d,n),max(d,n))|calc(min(d,u),max(d,u)))<<"\n";
    //当时左右区间分开或的
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值