T1 宝藏

解题思路

考场上一眼出 \(nlog^2\) 做法,然后没看见是 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 。

我们只需要知道每一种方案的总和了,最后乘上一个 \(A^n\) 。

设 \(g_{i,j,k}\) 表示有 多少个⻓度为 \(i\) 的正整数序列满足每一个数字不大于 \(j\) 且所有数字总和不超过 \(k\) 。

假设我们能够求出来这个值,考虑如何计算答案。

枚举选的牌中的最大值 \(j\) ,最大值个数 \(k\) ,以及选了 \(i\) 个小于 \(j\) 的牌,于是就有了:

\[\sum\limits_{i=0}^n\sum\limits_{j=1}^A\sum\limits_{k=1}^{n-i}g_{i,j-1,m-j\times k}\times \binom{n}{i}\sum\limits_{t=k}^{n-i}\binom{n-i}{t}\times(A-j)^{n-i-t}
\]

对于计算过方案数的两个序列就可以视为序列中的元素是等价的了,也就是再乘上一个可重集排列。

因为我们要选择 \(k\) 个 \(j\) 但是序列中不一定只有 \(k\) 个 \(j\) 因此我们需要让前面的牌的总和是 \(m-j\times k\) 然后枚举后面有多少个 \(j\) 同时计算剩下的取值的个数。

对于 \(g_{i,j,k}\) 可以通过枚举多少个大于 \(j\) 的数字进行计算,可以运用挡板法,由于挡板之间 1 的个数可能会超过 \(j\) 因此需要容斥一下:

\[g_{i,j,k}=\sum\limits_{t=0}^i(-1)^t\binom{i}{t}\binom{k-t\times j}{i}
\]

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;
}

NOIP模拟84(多校17)的更多相关文章

  1. NOIP模拟83(多校16)

    前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...

  2. Noip模拟79 2021.10.17(题目名字一样)

    T1 F 缩点缩成个$DAG$,然后根据每个点的度数计算期望值 1 #include<cstdio> 2 #include<cstring> 3 #include<vec ...

  3. Noip模拟18 2021.7.17 (文化课专场)

    T1 导弹袭击(数学) 显然,我们要找到最优的A,B使得一组a,b优于其他组那么可以列出: $\frac{A}{a_i}+\frac{B}{b_i}<\frac{A}{a_j}+\frac{B} ...

  4. Noip模拟55 2021.9.17(打表大胜利)

    T1 skip 普通$dp$很好打: $f[i]=max(f[j]-\sum_{k=1}^{K}k+a_i)$ 就是要注意边界问题很烦人. 1 #include<bits/stdc++.h> ...

  5. Noip模拟42 2021.8.17

    T1 卷 一看跟没有上司的舞会一样,直接敲了然后试个自己造的样例对了就跑了... 然而把它想简单了,乘积取模,还能比大小吗????? 显然不能 所以直接让对数的加和跟着$dp$直接一起跑,比大小的都用 ...

  6. Noip模拟8 2021.6.17

    T1 星际旅行 仔细一看,发现像一个欧拉路(简称一笔画). 满足"可以一笔画"的条件是: 1.所有点都有偶数条连边; 2.有偶数个点连奇数条边; 满足以上两个条件的任意一个即可一笔 ...

  7. NOIP模拟92(多校25)

    前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...

  8. Noip模拟84 2021.10.27

    以后估计都是用\(markdown\)来写了,可能风格会有变化 T1 宝藏 这两天老是会的题打不对,还是要细心... 考场上打的是维护\(set\)的做法,但是是最后才想出来的,没有维护对于是没有交. ...

  9. NOIP模拟85(多校18)

    前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...

随机推荐

  1. 任由文字肆意流淌,更自由的开源 Markdown 编辑器

    对于创作平台来说内容编辑器是十分重要的功能,强大的编辑器可以让创作者专注于创作"笔"下生花.而最好取悦程序员创作者的方法之一就是支持 Markdown 写作,因为大多数程序员都是用 ...

  2. hyperf从零开始构建微服务(二)——构建服务消费者

    阅读目录 构建服务消费者 安装json rpc依赖 安装JSON RPC客户端 server配置 编写业务代码 编写服务消费者类 consumer配置 配置 UserServiceInterface ...

  3. Hearthbuddy跳过ConfigurationWindow窗口

    Hearthbuddy版本为按照上一条博客修复后的版本. 打开Hearthbuddy后会弹出一个这样的窗口: 这个界面没有什么用,而且也没有人对此进行任何修改. 由于之前折腾版早就已经把这个界面跳过了 ...

  4. 前端框架VUE——安装及初始化

    本篇文章适合,想要学习 vue,但对 vue 又没有接触过的同学阅读,是非常基础的内容.告诉大家使用 vue 时的安装方式,及如何创建实例,展示内容. 一.安装方式 vue 是一种前端框架,所以使用前 ...

  5. request内部转发Demo

    // 转发的Demo1 import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import ja ...

  6. django框架开发流程

    python开发没有按目录划分,不像其它语言要先建一个包文件,所以python有必要先新建一个虚拟环境.这样不同的项目所依赖的环境和插件互不影响.虚拟环境的方法很多,这儿先用   virtualenv ...

  7. 机器学习——正则化方法Dropout

    1 前言 2012年,Dropout的想法被首次提出,受人类繁衍后代时男女各一半基因进行组合产生下一代的启发,论文<Dropout: A Simple Way to Prevent Neural ...

  8. 学习PHP中有趣的字符集国际化验证功能

    今天的内容非常简单,不过也很有趣.不知道大家有没有经历过这样的事情,就是在某些字体下,0 和 O 不好区分,1 和 l 也是很难看清楚.当然,现在大部分的编辑器和 IDE 的默认字体都是会选择那些比较 ...

  9. php nginx 路径批量配置

    * 假设 E:\upload 作为图片上传的位置 nginx 做web服务 * 创建文件conf.php 放到这个目录下 <?php function handleDir($it, &$ ...

  10. Redis 高可用篇:你管这叫主从架构数据同步原理?

    在<Redis 核心篇:唯快不破的秘密>中,「码哥」揭秘了 Redis 五大数据类型底层的数据结构.IO 模型.线程模型.渐进式 rehash 掌握了 Redis 快的本质原因. 接着,在 ...