11.6
魄罗蛙出的noip模拟题
前言
这个题的难度显然没有noip难,魄罗蛙良心出题人
1.二叉树上的询问(erchatree.in/out)
【题目描述】
给出一棵具有
我们规定,
并且,我们规定,对于所有的
显然,这是一棵二叉树,对于节点
现在,有
前序遍历:对每棵子树,先访问其根结点,再访问其左子树,最后访问其右子树。
例如,当
【输入格式】
第一行,输入两个整数
接下来
【输出格式】
对每个询问,输出一行,一个整数,表示对应询问的答案。
【样例】
【输入】
10 5
1
3
5
7
9
【输出】
1
8
6
10
5
【数据范围与提示】
对于 30% 的数据满足,
对于 60% 的数据满足,
对于 80% 的数据满足,
对于 100% 的数据满足,
有 40% 的数据,
【时空限制】
1000ms 128MB
分析
考场上的的无脑暴力
对于每个节点
若该节点为左儿子,必然是从父节点前序+1得来
若该节点为右儿子,必然是遍历完左儿子后第一个遍历的点
显然右儿子的答案就是父节点编号加上左儿子个数+1
那么问题就变成了求解每个子节点之前点的个数
一颗
若统计总数大于实际个数,那么就减去多余的数量即可
#include<bits/stdc++.h>
#define int __int128
using namespace std;
template<typename T>void read(T &x)
{
x=0; char c=getchar(); T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T>void wr(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) wr(x/10);
putchar((x-x/10*10)^48);
return ;
}//快读快写
int m;
int n,x;
int siz(int cat,int now,int real){//统计该节点子树大小 分别表示该点编号 目前大小 本层大小
if(cat>n){return now-min((cat-n),real);}
return siz(cat<<1|1,now<<1|1,real<<1);
}
int num(int sb){//往上递归求答案
if(sb==1)return 1ll;
if(sb&1){return num((sb-1)>>1)+siz(sb-1,1,1)+1;}
else{return num(sb>>1)+1;}
}
signed main()
{
read(n);read(m);
while(m--){
read(x);
int ans=num(x);
wr(ans);putchar('\n');
}
return 0;
}
/*
10 5
1
3
5
7
9
*/
2.追逐(gcd.in/out)
【题目描述】
众所周知,George_Plover chasing death
的缩写是gcd
。
同时,gcd又是最大公因数的意思,你需要求出。
其中
【输入格式】
输入6个整数,
【输出格式】
输出⼀⾏,表示题⽬描述式⼦中的计算结果,对 998244353 取余。
【样例】
【样例输入 #1】
1 2 1 2 8 4
【样例输出 #1】
2048
【提示】
【数据范围】:
对于30%的数据,满足
另有20%的数据,满足
对于100%的数据,
【时空限制】
2000ms 256MB
分析
先看
显然,不论
回到公因数的概念,什么叫公因呐,公因数即是
将
令
令
则
那么将其扩大到
我们需要优化枚举
在枚举
如果 此时的因子
那我们可以找到第一个
#include<bits/stdc++.h>
using namespace std;
const long long N=5010,P=998244353;
long long a,b,c,d,x,y,prime[N],cnt,cx[N],cy[N],both[N],num,ans=1;
long long vis[40010];
template<typename T>void read(T &x)
{
x=0; char c=getchar(); T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T>void wr(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) wr(x/10);
putchar((x-x/10*10)^48);
return ;
}
void init_()
{
for(long long i=2;i<=40000;++i)
{
if(vis[i]) continue;
prime[++cnt]=i;
for(long long j=2;i*j<=40000;++j)
vis[i*j]=1;
}
}
long long mpow(long long aa,long long bb)
{
long long res=1;
for(;bb;bb>>=1)
{
if(bb&1) res=res*aa%P;
aa=aa*aa%P;
}
return res;
}
int main()
{
freopen("gcd.in","r",stdin);
freopen("gcd.out","w",stdout);
init_();
read(a); read(b); read(c); read(d); read(x); read(y);
long long tx=x,ty=y;
for(long long i=1;i<=cnt;++i)
{
while(tx%prime[i]==0) ++cx[i],tx/=prime[i];
while(ty%prime[i]==0) ++cy[i],ty/=prime[i];
if(cx[i]&&cy[i]) both[++num]=i;
}
for(long long k=1;k<=num;++k)
{
long long sum=0,pk=both[k];
for(long long i=a,j=c;i<=b;++i)
{
while(j<=d&&cx[pk]*i>cy[pk]*j) ++j;
sum+=cx[pk]*i*(d-j+1)%(P-1);
sum%=P-1;
}
for(long long j=c,i=a;j<=d;++j)
{
while(i<=b&&cy[pk]*j>=cx[pk]*i) ++i;
sum+=cy[pk]*j*(b-i+1)%(P-1);
sum%=P-1;
}
ans*=mpow(prime[pk],sum);
ans%=P;
}
wr(ans);
return 0;
}
3.荷塘月色(lotus.in/out)
【题目描述】
在朦胧的月光下面,有
其中,第
现在,魄罗蛙计划选出一个子矩阵,将其中的池塘合并在一起,并且希望合并之后的大池塘里恰好有
现在,魄罗蛙想知道,有多少种不同的选法是满足要求的。
形式化来讲,问存在多少个四元组
【输入格式】
第一行,输入一个整数
接下来,
第一行,输入两个整数
接下来
接下来一行,输入一个整数,
保证对所有的
【输出格式】
输出
【样例】
【输入】
2
2 2
1 9
0 5
1
5 5
3 1 4 1 5
9 2 6 5 3
5 3 8 4 6
2 6 4 3 3
8 3 2 7 9
19
【输出】
2
7
【数据范围与时空限制】
存在 44% 的数据,满足
存在 24% 的数据,满足所有的
对 100% 的数据,满足题目描述中的数据范围。
【时空限制】
1000ms 128MB
分析
容易想到
显然我们的矩阵是单调递增的
但我们可以优化用二分优化一维,但感觉过不了,花半天实现不了二维的二分,就打了个能过
#include<bits/stdc++.h>
#pragma Optimize(2)
using namespace std;
#define MAXN 100001
#define int long long
template<typename T>void read(T &x)
{
x=0; char c=getchar(); T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T>void wr(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) wr(x/10);
putchar((x-x/10*10)^48);
return ;
}
long long kk,ans;
int n,m,T;
signed main() {
read(T);
while(T--)
{
read(n); read(m); ans=0;
int a,sum[n+1][m+1];
memset(sum,0,sizeof sum);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
read(a); sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a;
}
}
read(kk);
if(m>=n)
{
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=1;k<=m;k++)
{
int l=k,r=m,mid=(l+r)>>1,resl=l-1,resr=m+1;
while(l<=r)
{
mid=(l+r)>>1;
int now=sum[j][mid]-sum[j][k-1]-sum[i-1][mid]+sum[i-1][k-1];
if(now<kk) l=mid+1,resl=mid;
else r=mid-1;
}
l=k; r=m;
while(l<=r)
{
mid=(l+r)>>1;
int now=sum[j][mid]-sum[j][k-1]-sum[i-1][mid]+sum[i-1][k-1];
if(now>kk) r=mid-1,resr=mid;
else l=mid+1;
}
ans+=resr-resl-1;
}
}
}
}
else
{
for(int i=1;i<=m;i++)
{
for(int j=i;j<=m;j++)
{
for(int k=1;k<=n;k++)
{
int l=k,r=n,mid=(l+r)>>1,resl=l-1, resr=n+1;
while(l<=r)
{
mid=(l+r)>>1;
int now=sum[mid][j]-sum[k-1][j]-sum[mid][i-1]+sum[k-1][i-1];
if(now<kk) l=mid+1,resl=mid;
else r=mid-1;
}
l=k; r=n;
while(l<=r)
{
mid=(l+r)>>1;
int now=sum[mid][j]-sum[k-1][j]-sum[mid][i-1]+sum[k-1][i-1];
if(now>kk) r=mid-1,resr=mid;
else l=mid+1;
}
ans+=resr-resl-1;
}
}
}
}
wr(ans);putchar('\n');
}
return 0;
}
4.光华楼(fdu.in/out)
【题目描述】
光华楼很高。
现在给出楼层编号
某位大佬想到了一种传送方式。
楼层
1.如果
2.如果
可以发现,通过这种传送方式,从
特殊的,如果从
现在,你需要求出
由于
【输入格式】
输入共两行。
第一行,整数
第二行,一个二进制整数
【输出格式】
一行,一个整数, 答案对
【样例 #1】
【样例输入 #1】
3
111
【样例输出 #1】
40
【样例 #2】
【样例输入 #2】
6
110101
【样例输出 #2】
616
【提示】
样例1解释:
求和后
【时空限制】
1000ms 256MB
分析
不会,暴力30
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define int long long
using namespace std;
const int maxn = 300000;
const int mod = 998244353;
template<typename T>void read(T &x)
{
x=0; char c=getchar(); T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T>void wr(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) wr(x/10);
putchar((x-x/10*10)^48);
return ;
}
int n,bit[maxn],m,c,k,Ans;
char s[maxn];
int lim=10000;
__int128 ANS,K,N,MOD=__int128(998244353);
bool prim(int x)
{
for(int i=2;i*i<=x;i++) if(!(x%i)) return 0;
return 1;
}
signed main()
{
// freopen("fdu.in","r",stdin);
// freopen("fdu.out","w",stdout);
read(n);
if(n>=32)
{
if(prim(n))
{
K=__int128(n*2);
ANS=(((K*(1<<n)%MOD)%MOD-__int128(2*(n*2-2)))%MOD+MOD)%MOD;
wr(ANS);
return 0;
}
K=__int128(n*2);
wr(((K*((1<<n)%MOD))%MOD+MOD)%MOD);
return 0;
}
k=(1<<(n-1));
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=n;i++) c=s[i]-'0', bit[n-i]=c;
for(int i=0;i<n;i++) m|=(bit[i]<<i);
for(int i=0;i<=m;i++)
{
int st=i,tim=1;
if(st&1) st=(st-1)>>1;
else st=(st>>1)+k;
while(st!=i)
{
// cout<<st<<" ";
if(tim>=lim) {tim=0; break; }
if((st&1)) st=(st-1)/2,tim++;
else st=(st>>1)+k,tim++;
}
// cout<<tim<<"!"<<endl;;
Ans=(Ans+tim)>=mod?(Ans+tim-mod):Ans+tim;
}
wr(Ans);
return 0;
}
/*
3
111
6
110101
16
11111011101111111
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!