T1 宝藏

发现每个数成为中位数的长度是关于权值单调的。线段树二分判断是否合法,单调指针扫即可。

考场上写了二分,平添\(\log\)。

\(code:\)

T1
#include<bits/stdc++.h>
using namespace std; namespace IO{
typedef long long LL;
LL read(){
LL x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=300010;
int n,x,Q,ext,has[NN],ans[NN];
struct node{
int w,t;
bool operator<(const node& a)const{
return w<a.w;
}
}p[NN];
LL T; struct segmengt_tree{
#define ld rt<<1
#define rd (rt<<1)|1
int num[NN<<2];
LL sum[NN<<2];
void pushup(int rt){
num[rt]=num[ld]+num[rd];
sum[rt]=sum[ld]+sum[rd];
}
void update(int rt,int l,int r,int pos,int typ){
if(l==r){
num[rt]+=typ; sum[rt]+=typ*has[pos];
return;
}
int mid=l+r>>1;
if(pos<=mid) update(ld,l,mid,pos,typ);
else update(rd,mid+1,r,pos,typ);
pushup(rt);
}
LL query(int rt,int l,int r,int lmt){
if(!lmt) return 0;
if(num[rt]<=lmt) return sum[rt];
if(l==r) return 1ll*has[l]*lmt;
int mid=l+r>>1;
if(num[ld]>=lmt) return query(ld,l,mid,lmt);
return sum[ld]+query(rd,mid+1,r,lmt-num[ld]);
}
}big,sml; void solve(int id){
LL rest=T-has[p[id].t];
if(rest<0) return;
int l=1,r=n,res;
while(l<=r){
int mid=l+r>>1,lmt=mid>>1;
if(big.num[1]<lmt||sml.num[1]<lmt){ r=mid-1; continue; }
if(big.query(1,1,n,lmt)+sml.query(1,1,n,lmt)>rest) r=mid-1;
else l=mid+1,res=mid;
}
ckmax(ans[res],p[id].w);
} signed main(){
// freopen("treasure.in","r",stdin);
// freopen("treasure.out","w",stdout);
n=read(); T=read(); Q=read();
for(int i=1;i<=n;i++)
p[i].w=read(),has[i]=p[i].t=read(),ans[i]=-1;
sort(p+1,p+n+1); sort(has+1,has+n+1);
ext=unique(has+1,has+n+1)-has-1;
for(int i=1;i<=n;i++)
p[i].t=lower_bound(has+1,has+ext+1,p[i].t)-has;
for(int i=1;i<=n;i++) big.update(1,1,n,p[i].t,1);
for(int i=1;i<=n;i++){
big.update(1,1,n,p[i].t,-1);
solve(i);
sml.update(1,1,n,p[i].t,1);
}
for(int i=n-1;i;i--) ckmax(ans[i],ans[i+1]);
while(Q--){
x=read();
write(ans[x],'\n');
}
return 0;
}

T2 寻找道路

先把只走\(0\)边能到的点缩起来,之后要保证走到的点距离的字典序最小。

\(BFS\),每次取出队列中距离相等的点,先走\(0\)边再走\(1\)边,可以保证队列中距离是单调的。

\(code:\)

T2

#include<bits/stdc++.h>
using namespace std; namespace IO{
typedef long long LL;
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=1000010,MM=2000010,mod=1e9+7;
int n,m,st,idx,res[NN],head[NN];
int q[NN],l,r;
bool vis[NN];
vector<int>vec;
struct edge{ int to,nex,w; }e[MM];
void add(int a,int b,int c){ e[++idx]=(edge){b,head[a],c}; head[a]=idx; } void dfs(int s){
if(vis[s]) return;
vis[s]=1;
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to)
if(e[i].w) add(st,v,1);
else res[v]=0,dfs(v);
}
void bfs(){
q[l=r=1]=st; res[st]=0;
while(l<=r){
int tmp=res[q[l]];
vec.clear();
while(l<=r&&res[q[l]]==tmp) vec.push_back(q[l++]);
for(int x:vec)
for(int i=head[x],v=e[i].to;i;i=e[i].nex,v=e[i].to)
if(!e[i].w&&res[v]<0){
res[v]=(res[x]<<1)%mod;
q[++r]=v;
}
for(int x:vec)
for(int i=head[x],v=e[i].to;i;i=e[i].nex,v=e[i].to)
if(e[i].w&&res[v]<0){
res[v]=(res[x]<<1)%mod+1;
q[++r]=v;
}
}
} signed main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
n=read(); m=read(); st=n+1;
for(int a,b,c,i=1;i<=m;i++)
a=read(),b=read(),c=read(),add(a,b,c);
memset(res,-1,sizeof(res));
dfs(1); bfs();
for(int i=2;i<=n;i++) write(res[i],' ');
return puts(""),0;
}


T3 猪国杀

最优策略是取小的牌。

令至少拿\(i\)张牌的方案为\(f(i)\),那么\(ans\times A^n=\sum_{i=1}^nf(i)\)。

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

\[f(i)=\sum_{j=1}^A\sum_{k=1}^{n-i}g_{i,j-1,m-j\times k}\times\binom{n}{i}\sum_{t\geq k}\binom{n-i}{t}\times(A-j)^{n-i-t}
\]

枚举选的牌中的最大值\(j\),选的最大值个数\(k\)和最大值出现次数\(t\)可得。

考虑如何求\(g\)。可以通过容斥求解。

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

最后一个组合数考虑插板法,将\(k\)有顺序地分为\(i\)个正整数加和的方案数为\(\binom{k-1}{i-1}\),因为要满足强制\(t\)个数大于\(j\)(已固定位置),因此可以看作将\(k-t\times j\)划分为\(i\)个数,最后再在这\(t\)个数上各自加上\(j\),即可保证限制。

另外,因为\(g\)定义为加和不大于\(k\)的序列,因此可以看作将\(k+1\)划分为\(i+1\)个数,多出来的数即为\(i\)个数的和与\(k+1\)的差(至少为\(1\))。

综上,

\[ans\times A^n=\sum_{i=1}^n\sum_{j=1}^A\sum_{k=1}^{n-i}(\sum_{t=0}^i(-1)^t\binom{i}{t}\binom{m-k\times j-t\times(j-1)}{i})\times\binom{n}{i}\sum_{t\geq k}\binom{n-i}{t}(A-j)^{n-i-t}
\]

直接求和即可,复杂度约为\(\Theta(n^2m\log m)\)。

\(code:\)

T3

#include<bits/stdc++.h>
#define int long long
using namespace std; namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=110,mod=998244353;
int n,m,a;
int ans; namespace Combination{
int fac[NN*10],inv[NN*10];
int C(int x,int y){ return x<0||y<0||x<y?0:fac[x]*inv[y]%mod*inv[x-y]%mod; }
int qpow(int a,int b){
int res=1;
for(;b;b>>=1){
if(b&1) res=res*a%mod;
a=a*a%mod;
}
return res;
}
void init(){
fac[0]=inv[0]=1;
for(int i=1;i<=1000;i++) fac[i]=fac[i-1]*i%mod;
inv[1000]=qpow(fac[1000],mod-2);
for(int i=999;i;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
} using namespace Combination; signed main(){
freopen("legend.in","r",stdin);
freopen("legend.out","w",stdout);
n=read(); m=read(); a=read(); init();
for(int i=0;i<=n;i++)
for(int j=1;j<=a;j++)
for(int k=1;k<=n-i&&j*k<=m;k++){
int tmp=0,res=0;
for(int t=0;t<=i;t++)
tmp=(tmp+((t&1)?-1:1)*C(i,t)*C(m-k*j-t*(j-1),i)%mod)%mod;
for(int t=k;t<=n-i;t++)
res=(res+C(n-i,t)*qpow(a-j,n-i-t)%mod)%mod;
ans=(ans+tmp*C(n,i)%mod*res%mod)%mod;
}
ans=ans*qpow(qpow(a,n),mod-2)%mod;
write(ans,'\n');
return 0;
}


T4 数树

可以求出\(T1\)每个联通块中有多少个合法双射,最后除去\(T2\)自己与自己同构的方案。

设\(f_{i,s}\)表示\(i\)的儿子与\(T2\)中的点集\(s\)形成双射的方案数,每次枚举\(T2\)的根,在\(T1\)上做树上背包,最后将所有点作为\(T2\)根的方案累加即可。

说起来挺简单,但确实是神现题。

\(code:\)

T4

#include<bits/stdc++.h>
#define int long long
using namespace std; namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO; const int NN=3010,mod=998244353;
int n,m,idx,_idx,inv,id[15],head[NN],_head[NN];
int ans,son[15],f[NN][1<<10],g[NN][1<<10];
bool ed[15][15];
int u[15],v[15];
struct edge{ int to,nex; }e[NN<<1],_e[NN<<1];
void add(int a,int b){
e[++idx]=(edge){b,head[a]}; head[a]=idx;
e[++idx]=(edge){a,head[b]}; head[b]=idx;
}
void _add(int a,int b){
_e[++_idx]=(edge){b,_head[a]}; _head[a]=_idx; ed[a][b]=1;
_e[++_idx]=(edge){a,_head[b]}; _head[b]=_idx; ed[b][a]=1;
}
int qpow(int a,int b){
int res=1;
for(;b;b>>=1){
if(b&1) res=res*a%mod;
a=a*a%mod;
}
return res;
}
void _dfs(int s,int fa){
for(int i=_head[s],v=_e[i].to;i;i=_e[i].nex,v=_e[i].to)
if(v!=fa) son[s]|=(1<<v-1),_dfs(v,s);
}
void dfs(int s,int fa){
f[s][0]=1;
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to) if(v!=fa){
dfs(v,s);
for(int j=1;j<=m;j++) if(f[v][son[j]])
for(int k=0;k<(1<<m);k++) if(f[s][k]&&!(k&(1<<j-1)))
(g[s][k|(1<<j-1)]+=f[s][k]*f[v][son[j]])%=mod;
for(int k=1;k<(1<<m);k++) f[s][k]=g[s][k];
}
} signed main(){
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
n=read();
for(int a,b,i=1;i<n;i++)
a=read(),b=read(),add(a,b);
m=read();
for(int i=1;i<m;i++)
u[i]=read(),v[i]=read(),_add(u[i],v[i]);
for(int i=1;i<=m;i++) id[i]=i;
do{
bool flag=1;
for(int i=1;i<m;i++)
if(!ed[id[u[i]]][id[v[i]]]){ flag=0; break; }
inv+=flag;
}while(next_permutation(id+1,id+m+1));
inv=qpow(inv,mod-2);
for(int i=1;i<=m;i++){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(son,0,sizeof(son));
_dfs(i,0); dfs(1,0);
for(int j=1;j<=n;j++)
(ans+=f[j][son[i]])%=mod;
}
write(ans*inv%mod,'\n');
return 0;
}


2021.10.27考试总结[冲刺NOIP模拟17]的更多相关文章

  1. 2021.10.26考试总结[冲刺NOIP模拟16]

    T1 树上的数 \(DFS\)一遍.结构体存边好像更快? \(code:\) T1 #include<bits/stdc++.h> using namespace std; namespa ...

  2. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  3. NOIP模拟 17.8.15

    NOIP模拟17.8.15 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...

  4. NOIP模拟 17.8.20

    NOIP模拟17.8.20 A.阶乘[题目描述]亲爱的xyx同学正在研究数学与阶乘的关系,但是他喜欢颓废,于是他就制作了一个和阶乘有关系的数学游戏:给出两个整数 n,m,令 t = !n,每轮游戏的流 ...

  5. NOIP模拟 17.8.18

    NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也 ...

  6. NOIP模拟 17.8.16

    NOIP模拟17.8.16 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...

  7. NOIP模拟 17.8.14

    NOIP模拟17.8.14 (天宇哥哥考察细心程度的题) [样例解释]如果删去第一个 1:在[3,1,2]中有 3 个不同的数如果删去 3:在[1,1,2]中有 2 个不同的数如果删去第二个 1:在[ ...

  8. NOIP模拟17.9.21

    NOIP模拟17.9.21 3 58 145 201 161.5 样例输出21.6 数据规模及约定对于40% 的数据,N <= 20对于60% 的数据,N <= 1000对于100% 的数 ...

  9. NOIP模拟 17.8.17

    NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 ...

随机推荐

  1. Redis集群的搭建及与SpringBoot的整合

    1.概述 之前聊了Redis的哨兵模式,哨兵模式解决了读的并发问题,也解决了Master节点单点的问题. 但随着系统越来越庞大,缓存的数据越来越多,服务器的内存容量又成了问题,需要水平扩容,此时哨兵模 ...

  2. 在C#中使用RSA进行加密和解密

    这篇文章向您展示了如何在c#.net Windows窗体应用程序中使用RSA算法对字符串进行加密和解密.RSA是由Ron Rivest,Adi Shamir和Leonard Adleman开发的非对称 ...

  3. WPF Prism8.0中注册Nlog日志服务

    无论是Nlog还是Serilog, 它们都提供了如何快速在各类应用程序当中的快速使用方法. 尽管,你现在无论是在WPF或者ASP.NET Core当中, 都可以使用ServiceCollection来 ...

  4. Javascript 判断 iframe 中的变量是否为对象

    Javascript 判断 iframe 中的变量是否为对象 前言 公司之前的项目中,为了实现模块化,在 web 后端使用了 iframe 来组织框架和页面.由于当时没有很好地规划,iframe 子页 ...

  5. Anaconda配置国内镜像源

    1. 为conda配置(清华)镜像源 使用conda进行安装时,访问的是国外的网络,所以下载和安装包时会特别慢.我们需要更换到国内镜像源地址,这里我更换到国内的清华大学地址.(永久添加镜像) Wind ...

  6. 洛谷P1090——合并果子(贪心)

    https://www.luogu.org/problem/show?pid=1090 题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合 ...

  7. error: subscripted value is neither array nor pointer问题解决

    在运行程序的时候报错:error: subscripted value is neither array nor pointer 原因分析:下标值不符合数组或指针要求,即操作的对象不允许有下标值. 出 ...

  8. jQuery <= 1.11.3 DomXSS漏洞

    听团里说WordPress又爆跨站漏洞了:" XSS漏洞在Jetpack和二十五默认主题影响百万WordPress用户 ",分析发现原来是jQuery老版本的DOM XSS漏洞[错 ...

  9. 关于URL encode和parse

    from urllib import parses = 'https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&tn=baidu& ...

  10. 2020牛客NOIP赛前集训营-提高组(第三场)C-牛半仙的妹子Tree【虚树,最短路】

    正题 题目链接:https://ac.nowcoder.com/acm/contest/7609/C 题目大意 给出\(n\)个点的一棵树,\(m\)个时刻各有一个操作 标记一个点,每个点被标记后的每 ...