NOIP模拟84(多校17)
T1 宝藏
解题思路#
考场上一眼出 做法,然后没看见是 1s 3e5
的数据,我竟然以为自己切了??
考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的做法指针好像并不满足单调性。。
口胡一下正解,做法差不多,只不过枚举的方式改变了,但是都需要先对于 w 进行排序,枚举每一种长度的序列,单调指针维护最大的合法的值。
这个是有单调性的,然后主席树或者权值线段树维护均可。
code#
其实是假做法
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=3e5+10,M=1e6+10;
int n,m,q,lim,ans[N];
struct Node{int w,t;}s[N];
struct Segment_Tree
{
int root,all;
struct node{int siz,dat;}tre[M<<2];
#define push_up(x) tre[x].dat=tre[ls].dat+tre[rs].dat,tre[x].siz=tre[ls].siz+tre[rs].siz
void insert(int x,int l,int r,int pos,int val)
{
if(l==r) return tre[x].siz+=val,tre[x].dat+=val*pos,void();
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos,val);
else insert(rs,mid+1,r,pos,val);
push_up(x);
}
int query(int x,int l,int r,int k)
{
if(!tre[x].siz||!k) return 0;
if(l==r) return tre[x].dat*k/tre[x].siz;
int mid=(l+r)>>1;
if(tre[ls].siz>k) return query(ls,l,mid,k);
return tre[ls].dat+query(rs,mid+1,r,k-tre[ls].siz);
}
}T1,T2;
bool comp(Node x,Node y){return x.w<y.w;};
#undef int
int main()
{
#define int long long
freopen("treasure.in","r",stdin); freopen("treasure.out","w",stdout);
n=read(); m=read(); q=read(); memset(ans,-1,sizeof(ans));
for(int i=1;i<=n;i++) s[i].w=read(),s[i].t=read(),lim=max(lim,s[i].t);
sort(s+1,s+n+1,comp); for(int i=1;i<=n;i++) T2.insert(1,0,lim,s[i].t,1);
for(int i=1,val=0;i<=n;i++)
{
T2.insert(1,0,lim,s[i].t,-1); val=min(val,min(i-1,n-i));
while(val<min(i-1,n-i)&&T1.query(1,1,lim,val+1)+T2.query(1,1,lim,val+1)+s[i].t<=m) val++;
while(val>0&&T1.query(1,1,lim,val)+T2.query(1,1,lim,val)+s[i].t>m) val--;
ans[val]=max(ans[val],s[i].w); T1.insert(1,0,lim,s[i].t,1);
}
for(int i=n/2;i>=0;i--) ans[i]=max(ans[i],ans[i+1]);
while(q--){int x;x=read();printf("%lld\n",ans[min(n,x/2)]);}
return 0;
}
T2 寻找道路
解题思路#
首先考虑去除前导 0 的影响,直接搜索一遍查找所有到 1 节点距离为 0 的点记录下来就好了。
剩下的部分就是字典序以及长度的问题了,那么长度的问题直接 BFS 就可以了。
字典序大小的话,对于队列中长度一致并且数字序列相同的一起拿出来,然后优先扫 0 边权的边再扫 1 边权的边。
标记一下,保证每个节点只访问一次。
code#
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e6+10,mod=1e9+7,INF=1e18;
int n,m,top,sta[N],len[N],dis[N];
int tot=1,head[N],ver[N<<1],nxt[N<<1],edge[N<<1];
vector<int> dis0;
queue<int> q;
bool vis[N];
void add_edge(int x,int y,int val)
{
ver[++tot]=y; edge[tot]=val;
nxt[tot]=head[x]; head[x]=tot;
}
#undef int
int main()
{
#define int long long
freopen("path.in","r",stdin); freopen("path.out","w",stdout);
n=read(); m=read(); memset(len,0x3f,sizeof(len)); dis[1]=len[1]=0;
for(int i=1,x,y,z;i<=m;i++) x=read(),y=read(),z=read(),add_edge(x,y,z);
q.push(1); dis0.push_back(1);
while(!q.empty())
{
int x=q.front(); q.pop();
for(int i=head[x];i;i=nxt[i])
if(!vis[ver[i]]&&!edge[i])
vis[ver[i]]=true,dis0.push_back(ver[i]),q.push(ver[i]);
}
for(auto it:dis0) q.push(it),dis[it]=len[it]=0;
while(!q.empty())
{
top=0; sta[++top]=q.front(); q.pop();
while(!q.empty()&&len[q.front()]==len[sta[1]]&&dis[q.front()]==dis[sta[1]])
sta[++top]=q.front(),q.pop();
for(int i=1;i<=top;i++)
{
int x=sta[i];
for(int j=head[x];j;j=nxt[j])
{
int to=ver[j],val=edge[j];
if(val||vis[to]||len[to]<=len[x]+1) continue;
len[to]=len[x]+1; dis[to]=dis[x]*2%mod;
vis[to]=true; q.push(to);
}
}
for(int i=1;i<=top;i++)
{
int x=sta[i];
for(int j=head[x];j;j=nxt[j])
{
int to=ver[j],val=edge[j];
if(!val||vis[to]||len[to]<=len[x]+1) continue;
len[to]=len[x]+1; dis[to]=(dis[x]*2+1)%mod;
vis[to]=true; q.push(to);
}
}
}
for(int i=2;i<=n;i++) printf("%lld ",len[i]>=INF?-1ll:dis[i]);
return 0;
}
T3 猪国杀
解题思路#
其实是个假期望,计数 DP 。
我们只需要知道每一种方案的总和了,最后乘上一个 。
设 表示有 多少个⻓度为 的正整数序列满足每一个数字不大于 且所有数字总和不超过 。
假设我们能够求出来这个值,考虑如何计算答案。
枚举选的牌中的最大值 ,最大值个数 ,以及选了 个小于 的牌,于是就有了:
对于计算过方案数的两个序列就可以视为序列中的元素是等价的了,也就是再乘上一个可重集排列。
因为我们要选择 个 但是序列中不一定只有 个 因此我们需要让前面的牌的总和是 然后枚举后面有多少个 同时计算剩下的取值的个数。
对于 可以通过枚举多少个大于 的数字进行计算,可以运用挡板法,由于挡板之间 1 的个数可能会超过 因此需要容斥一下:
code#
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=110,M=1010,mod=998244353;
int n,m,lim,mx,ans,fac[M],ifac[M];
void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int power(int x,int y,int p=mod)
{
int temp=1;
while(y)
{
if(y&1) temp=temp*x%p;
x=x*x%p; y>>=1;
}
return temp;
}
int C(int x,int y){return x<y?0:fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
int g(int i,int j,int k)
{
int sum=0;
for(int p=0,sym=1;p<=i;p++,sym=-sym)
{
int temp=C(i,p)*C(k-p*j,i)%mod;
if(temp) add(sum,sym*temp+((~sym)?0:mod));
else break;
}
return sum;
}
#undef int
int main()
{
#define int long long
freopen("legend.in","r",stdin); freopen("legend.out","w",stdout);
n=read(); m=read(); lim=read(); mx=max(n,max(m,lim));
fac[0]=ifac[0]=1; for(int i=1;i<=mx;i++) fac[i]=fac[i-1]*i%mod;
ifac[mx]=power(fac[mx],mod-2); for(int i=mx-1;i>=1;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
for(int i=0;i<=n;i++)
for(int j=1;j<=lim;j++)
for(int k=1;k<=n-i;k++)
{
int base=0,temp=C(n,i)%mod*g(i,j-1,m-j*k)%mod;
if(!temp) continue;
for(int p=k;p<=n-i;p++)
{
int temp=C(n-i,p); if(!temp) break;
add(base,temp*power(lim-j,n-i-p)%mod);
}
if(base) add(ans,base*temp%mod);
}
printf("%lld",ans*power(power(lim,n),mod-2)%mod); return 0;
}
T4 数树
解题思路#
枚举以哪个节点为根以及子树和 T2 的匹配程度来判断。
具体实现可以 Hash+素数 防止重复。
code#
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=3e3+10,M=20,bas=23,mod=998244353;
int n,m,cnt,ans,pri[N],siz[N];
int tot=1,head[N],ver[N<<1],nxt[N<<1];
ull has[N];
unordered_map<ull,int> ys,f[N];
unordered_map<ull,bool> can,mp;
vector<int> v[M];
bitset<N> vis;
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void Get_Prime()
{
for(int i=2;i<=1000;i++)
{
if(!vis[i]) pri[++cnt]=i;
for(int j=1;j<=cnt&&pri[j]*i<=1000;j++)
{
vis[i*pri[j]]=true;
if(i%pri[j]==0) break;
}
}
}
void pre_dfs(int x,int fa)
{
siz[x]=has[x]=1;
for(auto to:v[x])
{
if(to==fa) continue;
pre_dfs(to,x); siz[x]+=siz[to];
has[x]+=has[to]*pri[siz[to]+bas];
}
mp.insert(make_pair(has[x],true));
ys.insert(make_pair(has[x],siz[x]+bas));
}
void dfs(int x,int fa)
{
f[x].insert(make_pair(1,1));
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i]; if(to==fa) continue;
unordered_map<ull,int> temp=f[x]; dfs(to,x);
for(auto it1:temp) for(auto it2:f[to])
{
ull rec=it1.first+it2.first*pri[ys.find(it2.first)->second];
f[x][rec]=(f[x][rec]+it1.second*it2.second)%mod;
}
}
vector<ull> dela;
for(auto it:f[x]) if(mp.find(it.first)==mp.end()) dela.push_back(it.first);
for(auto it:dela) f[x].erase(it);
}
#undef int
int main()
{
#define int long long
freopen("count.in","r",stdin); freopen("count.out","w",stdout);
n=read(); Get_Prime();
for(int i=1,x,y;i<n;i++)
x=read(),y=read(),
add_edge(x,y),add_edge(y,x);
m=read();
for(int i=1,x,y;i<m;i++)
x=read(),y=read(),
v[x].push_back(y),v[y].push_back(x);
for(int i=1;i<=m;i++) pre_dfs(i,0),can.insert(make_pair(has[i],true));
dfs(1,0);
for(auto it:can)
for(int i=1;i<=n;i++)
if(f[i].find(it.first)!=f[i].end())
ans=(ans+f[i].find(it.first)->second)%mod;
printf("%lld",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)