题目①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;
}
解:(最近太懒,原谅我把昨天的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";
//当时左右区间分开或的
}