以后估计都是用\(markdown\)来写了,可能风格会有变化

T1 宝藏

这两天老是会的题打不对,还是要细心。。。

考场上打的是维护\(set\)的做法,但是是最后才想出来的,没有维护对于是没有交。。

然后觉得细节太多于是下午来的就去打了比较好搞得权值线段树

基本思想就是用一个指针\(pos\)指向当前需要更新的答案(\(pos\times 2+1\)是题目输入的选择的数的个数,这样解释应该就好懂了)

那么考虑先将所有宝藏按照价值从小到大排序,发现从最后开始向前扫每一个宝藏,他可以更新的\(pos\)是单调递增的

例如,当前考虑下标为\(x\)的宝藏价值为中位数最大值的时候,

他的可以更新的这个\(pos\)值域取在\([pos,\min(n-x,x-1)]\)一段区间,

那么我们只需要看,从\(x\)的左边和右边分别选择\(pos\)个宝藏,他们的\(\sum t\)是否有可能小于\(T\),

显然每次找到最小的前\(pos\)个\(t\)的\(\sum\)是最优的,所以开两颗权值线段树分别维护当前的\(x\)左边和右边的值即可

treasure
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int NN=3e5+5;
namespace AE86{
auto 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;
};
auto write=[](int x,char opt='\n'){
char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
for(short i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);
};
}using namespace AE86;
int n,T,Q,x,ans[NN],mx,dis[NN];
struct node{
int w,t;
bool operator<(const node&a)const{
return w==a.w?t<a.t:w<a.w;
}
}p[NN];
struct SNOWtree{
#define lid (id<<1)
#define rid (id<<1|1)
int ll[NN<<2],rr[NN<<2],nm[NN<<2],sm[NN<<2];
inline void pushup(int id){if(ll[id]==rr[id])return;nm[id]=nm[lid]+nm[rid];sm[id]=sm[lid]+sm[rid];}
inline void build(int id,int l,int r){ll[id]=l;rr[id]=r;if(l==r)return;int mid=l+r>>1;build(lid,l,mid);build(rid,mid+1,r);}
inline void insert(int id,int pos,int v){
if(ll[id]==rr[id])return nm[id]+=v,sm[id]+=v*dis[pos],void();int mid=ll[id]+rr[id]>>1;
if(pos<=mid)insert(lid,pos,v); else insert(rid,pos,v); pushup(id);
}
inline int query(int id,int lim){
if(!lim) return 0;
if(nm[id]<=lim) return sm[id];
if(ll[id]==rr[id]) return dis[ll[id]]*lim;
int mid=ll[id]+rr[id]>>1;
if(lim<=nm[lid]) return query(lid,lim);
return sm[lid]+query(rid,lim-nm[lid]);
}
}ri,le;
int pos;
auto solve=[](int x){
int r=min(n-x,x-1); if(pos>r) return;
while(pos<=r){
int tot=ri.query(1,pos)+le.query(1,pos)+dis[p[x].t];
if(tot<=T) ans[pos*2+1]=p[x].w,++pos; else break;
}
};
namespace WSN{
inline short main(){
// freopen("in.in","r",stdin);freopen("bl.out","w",stdout);
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(),p[i].t=read(),dis[i]=p[i].t;
sort(p+1,p+n+1); memset(ans,-1,sizeof(ans));
sort(dis+1,dis+n+1); mx=unique(dis+1,dis+n+1)-dis-1;
for(int i=1;i<=n;i++) p[i].t=lower_bound(dis+1,dis+mx+1,p[i].t)-dis;
ri.build(1,1,mx);le.build(1,1,mx);
for(int i=1;i<=n;++i) le.insert(1,p[i].t,1);
for(int i=n;i;--i) le.insert(1,p[i].t,-1),solve(i),ri.insert(1,p[i].t,1);
while(Q--) x=read(),write(ans[x]);
return 0;
}
}
signed main(){return WSN::main();}

T2 寻找道路

对不起,坏孩子没有打正解,直接使用\(bitset\)可以淼过去

考场上打了一半的\(bitset\)然后发现使用\(dijkstra\)无法优化其对于堆优化时候的比较函数

然后当时不知道咋想的,也没有试一试\(spfa\),\(spfa\)只有一次比较,写起来非常方便

只要写了\(spfa+bitset\)就可以切掉了,但是只能说是淼过去的

非常好写,就是注意删除前导\(0\)就可以了

path
#include<bits/stdc++.h>
#define int long long
#define si(i,x) for(int i=head[x],y=e[i].to;i;i=e[i].next,y=e[i].to)
using namespace std;
const int NN=2e6+5,mod=1e9+7;
namespace AE86{
auto 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;
};
auto write=[](int x,char opt='\n'){
char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
for(short i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);
};
}using namespace AE86;
int n,m;
struct SNOW{int to,val,next;}e[NN];int head[NN],rp=1;
auto add=[](int x,int y,int z){e[++rp]=SNOW{y,z,head[x]};head[x]=rp;};
int dis[NN],wei[NN];
bitset<1001> bt[NN],tmp;
bool vis[NN];
queue<int>q;
auto spfa=[](){
for(int i=1;i<=n;i++)
dis[i]=1e18,wei[i]=1000,bt[i].flip();
q.push(1); vis[1]=true;
dis[1]=0; wei[1]=1; bt[1].reset(); bt[1]=0;
while(!q.empty()){
int x=q.front(); q.pop(); vis[x]=false;
si(i,x){
bool cmp=0; int wi=wei[x]+1;
if(bt[x][wei[x]]==0) --wi;
tmp=bt[x]<<1; tmp[1]=e[i].val;
if(wei[y]>wi) cmp=1;
else if(wei[y]<wi) cmp=0;
else{
for(int j=wei[y];j;--j){
if(bt[y][j]>tmp[j]) {cmp=1;break;}
else if(bt[y][j]<tmp[j]) {cmp=0;break;}
}
}
if(cmp){
bt[y]=tmp; wei[y]=wi;
dis[y]=(dis[x]*2%mod+e[i].val)%mod;
if(!vis[y]){
vis[y]=true;
q.push(y);
}
}
}
}
};
namespace WSN{
inline short main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
n=read();m=read();
for(int i=1,u,v,w;i<=m;i++)
u=read(),v=read(),w=read(),add(u,v,w);
spfa();
for(int i=2;i<=n;i++)
if(dis[i]>=1e18) write(-1,' ');
else write(dis[i],' ');
puts("");
return 0;
}
}
signed main(){return WSN::main();}

T3 猪国杀

又搞这一套,又想吓我,已经无法被吓倒了

不过题目还是很神仙的假期望,真计数

设方案数为\(ans\),那么答案就是

\(ans=\sum\limits_{i=0}^{n}\sum\limits_{j=1}^{A}\sum\limits_{k=1}^{n-i}g_{i,j-1,m-j*k}\times C_n^i\sum\limits_{t\geq k}C_{n-i}^{t}\times(A-j)^{n-i-t}\)

其中\(g_{i,j,k}\)表示有多少个长度为\(i\)的序列满足每一个数字都不大于\(j\)且所有数字的总和不大于\(k\)

以上式子可以理解为枚举序列的长度,然后枚举最大值\(j\),然后再枚举最大值的个数\(k\),然后剩下的\(n-i\)个可以在去掉最大值的限制后随便选

你可能会问,这个算方案数的式子为什么不用考虑每次的贡献?

实际上他每个合法的序列计算的次数正好为他做的贡献数,即每个合法序列都会计算\(i+k\)次

那么考虑容斥出\(g_{i,j,k}=\sum\limits_{t=0}^{i}(-1)^t\times C_i^t\times C_{k-j*t}^{i}\)

那么原式的转化我就不写了,随便代一下就出来了,直接照这个式子抄就可以了,把没有贡献的地方直接跳过不计算

legend
#include<bits/stdc++.h>
#define int long long
#define si(i,x) for(int i=head[x],y=e[i].to;i;i=e[i].next,y=e[i].to)
using namespace std;
const int NN=101,MM=3001,mod=998244353; namespace AE86{
auto 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;
};
auto write=[](int x,char opt='\n'){
char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
for(short i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);
};
}using namespace AE86; int n,m,A,ans; namespace Math{
int h[MM],v[MM];
auto qmo=[](int a,int b,int ans=1){
int c=mod;for(;b;b>>=1,a=a*a%c)if(b&1)ans=ans*a%c;
return ans;
};
auto inv=[](int x){return qmo(x,mod-2);};
auto prework=[](){
h[0]=h[1]=1; v[0]=v[1]=1; for(int i=2;i<MM;++i)h[i]=h[i-1]*i%mod;
v[MM-1]=inv(h[MM-1]); for(int i=MM-2;i>=2;--i)v[i]=v[i+1]*(i+1)%mod;
};
auto C=[](int n,int m){return (n<m||n<0||m<0) ? 0 : (h[n]*v[n-m]%mod*v[m]%mod);};
}using namespace Math; namespace WSN{
inline short main(){
freopen("legend.in","r",stdin);
freopen("legend.out","w",stdout);
n=read();m=read();A=read();prework();
for(int i=0;i<=n;++i){
for(int j=1;j<=A;++j){
for(int k=1;k<=n-i;++k){
if(m-k*j<0)continue;
int tmp=0,res=0,bs=1;
for(int t=0;t<=i&&m-k*j-t*(j-1)>=i;++t,bs=-bs)
tmp=(tmp+bs*C(i,t)%mod*C(m-k*j-t*(j-1),i)%mod+mod)%mod;
tmp=tmp*C(n,i)%mod;
for(int t=k;t<=n-i;++t)
res=(res+C(n-i,t)*qmo(A-j,n-i-t)%mod)%mod;
ans=(ans+tmp*res%mod)%mod;
}
}
}
write(ans*inv(qmo(A,n))%mod);
return 0;
}
}
signed main(){return WSN::main();}

T4 数树

数据范围提示状态压缩,那么考虑如何设状态

设计状态\(f[x][S]\)表示\(x\)子树中的点集为\(S\)的方案数

例如,\(S=0001110\)就表示\(2,3,4\)这三个点是某一个点的子孙节点

那么因为\(T2\)的形状对于不同的节点做根可能会不一样,所以以每一个节点做根都跑一边\(dp\)

然后注意去重,具体操作就是用\(map\)预处理出会重复算多少次,最后的\(dp\)数组再把算重复的除掉就行了

count
#include<bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int NN=3005,mod=998244353;
namespace AE86{
auto 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;
};
auto write=[](int x,char opt='\n'){
char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
for(short i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);
};
}using namespace AE86;
auto qmo=[](int a,int b,int ans=1){
int c=mod;for(;b;b>>=1,a=a*a%c)if(b&1)ans=ans*a%c;
return ans;
};auto inv=[](int x){return qmo(x,mod-2);}; int n,m,v[11],S[1<<10],tot,root,T[11],dp[NN][1<<10],tmp[11];
vector<int> son[11];
struct Graph{
#define star(e,i,x) for(int i=e.head[x],y=e.to[i];i;i=e.nxt[i],y=e.to[i])
int to[NN<<1],nxt[NN<<1],head[NN],rp;
inline void add(int x,int y){
to[++rp]=y; nxt[rp]=head[x]; head[x]=rp;
to[++rp]=x; nxt[rp]=head[y]; head[y]=rp;
}
}e,g;
unordered_map<int,bool>mp;
unordered_map<int,int>t[11];
inline void dfs(int f,int x,int bs){
S[x]|=(1<<x-1);tot+=bs;
star(g,i,x) if(y!=f){
son[x].pb(y); dfs(x,y,bs*10);
++t[x][T[y]];
S[x]|=S[y];T[x]+=T[y];
}
star(g,i,x) if(y!=f) if(t[x].find(T[y])!=t[x].end())
tmp[x]=tmp[x]*v[t[x][T[y]]]%mod,t[x].erase(T[y]);
T[x]+=bs;
}
int res[1<<10],ans;
inline void DP(int f,int x){
for(int i=0;i<m;i++) dp[x][1<<i]=1;
star(e,i,x) if(y!=f){
DP(x,y);
for(int j=1;j<(1<<m);j++) res[j]=dp[x][j];
for(int j=1;j<(1<<m);j++) if(dp[x][j])
for(int k=1;k<=m;k++) if(!(j&S[k])&&dp[y][S[k]])
dp[x][S[k]|j]=(dp[x][S[k]|j]+dp[y][S[k]]*res[j]%mod)%mod;
}
for(int i=1;i<=m;i++) dp[x][S[i]]=dp[x][S[i]]*tmp[i]%mod;
ans=(ans+dp[x][(1<<m)-1])%mod;
}
namespace WSN{
inline short main(){
freopen("count.in","r",stdin);freopen("count.out","w",stdout);
v[0]=1; for(int i=1;i<=10;i++) v[i]=v[i-1]*inv(i)%mod;
n=read();for(int i=1;i<n;i++)e.add(read(),read());
m=read();for(int i=1;i<m;i++)g.add(read(),read());
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++)t[j].clear(),son[j].clear(),tmp[j]=1;
memset(S,0,sizeof(S));
memset(T,0,sizeof(T));
memset(dp,0,sizeof(dp));
tot=0; root=i;
dfs(0,root,1);
if(mp.find(tot)==mp.end())
mp[tot]=true,DP(0,1);
}
write(ans);
return 0;
}
}
signed main(){return WSN::main();}

Noip模拟84 2021.10.27的更多相关文章

  1. Noip模拟70 2021.10.6

    T1 暴雨 放在第一道的神仙题,不同的做法,吊人有的都在用线段树维护$set$预处理 我是直接$dp$的,可能代码的复杂度比那种的稍微小一点 设$f[i][j][p][0/1]$表示考虑了前$i$列, ...

  2. Noip模拟69 2021.10.5

    考场拼命$yy$高精度结果没学好$for$循环痛失$50pts$,当场枯死 以后一定打对拍,要不考后会... T1 石子游戏 首先要知道典型的$NIM$博弈,就是说如果所有堆石子个数的异或和为$0$则 ...

  3. Noip模拟76 2021.10.14

    T1 洛希极限 上来一道大数据结构或者单调队列优化$dp$ 真就没分析出来正解复杂度 正解复杂度$O(q+nm)$,但是据说我的复杂度是假的 考虑一个点转移最优情况是从它上面的一个反$L$形转移过来 ...

  4. Noip模拟63 2021.9.27(考场惊现无限之环)

    T1 电压机制 把题目转化为找那些边只被奇数环包含. 这样的话直接$dfs$生成一棵树,给每个点附上一个深度,根据其他的非树边都是返祖边 可以算出环内边的数量$dep[x]-dep[y]+1$,然后判 ...

  5. Noip模拟81 2021.10.20

    T1 语言 比较简单的题,然后就瞎写了,所以考场上就我一个写了线段树的,所以我的常数.... 所以就枚举动词的位置,找前面后面有没有出现$4$即可 1 #include<bits/stdc++. ...

  6. Noip模拟83 2021.10.26

    T1 树上的数 有手就能在衡中$OJ$上过,但是$WaitingCoders$不行,就是这样 必须使用$O(n)$算法加上大力卡常,思路就是找子树内没更新的更新,更新过了直接$return$ 1 #i ...

  7. Noip模拟80 2021.10.18

    预计得分:5 实际得分:140?????????????? T1 邻面合并 我考场上没切掉的大水题....(证明我旁边的cty切掉了,并觉得很水) 然而贪心拿了六十,离谱,成功做到上一篇博客说的有勇气 ...

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

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

  9. Noip模拟74 2021.10.11

    T1 自然数 考场上当我发现我的做法可能要打线段树的时候,以为自己百分之百是考虑麻烦了 但还是打了,还过掉了所有的样例,于是十分自信的就交了 正解还真是线段树,真就第一题数据结构 但是包括自己造的小样 ...

随机推荐

  1. TCP头部格式和封装

    文章目录 12.3 TCP头部和封装 12.3.1 端口号 12.3.2 序列号 12.3.3 头部长度 12.3.4 相关控制位 12.3.5 窗口大小 12.3.6 校验和 12.3.7 选项字段 ...

  2. Identity角色管理三(创建角色)

    首先创建视图模型 using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Shop.Vi ...

  3. 机器学习——集成学习(Bagging、Boosting、Stacking)

    1 前言 集成学习的思想是将若干个学习器(分类器&回归器)组合之后产生一个新学习器.弱分类器(weak learner)指那些分类准确率只稍微好于随机猜测的分类器(errorrate < ...

  4. UVA 11853 Paintball(几何数学+DFS)

    https://vjudge.net/problem/UVA-11853 根据题意描述,相当于在一个正方形中有若干个圆形障碍物,问是否能从左边界走到右边界.判断是否有解需要一点创造性的思维:不妨把正方 ...

  5. 【OI】WERTYU UVa 10082

    题目: A common typing error is to place the hands on the keyboard one row to the right of the correct ...

  6. PHP中的日期相关函数(一)

    日期相关的操作函数是我们在日常的工作开发中最常接触到的功能.当然,大部分同学可能最多用到的就是 date() . time() 这两个函数,我们今天先不讲这两个函数,或许后面的文章也不太会讲它们,毕竟 ...

  7. 分布式文件系统FastDFS在CentOS7上的安装及与Springboot的整合

    1. 概述 FastDFS 是目前比较流行的分布式文件系统,可以很容易的实现横向扩展.动态扩容.灾备.高可用和负载均衡. FastDFS 的服务分为 tracker 服务 和 storage 服务,  ...

  8. 《HelloGitHub》第 66 期

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这里有实战项目.入门教程.黑科技.开源书籍.大厂开源项目等,涵盖多种编程语言 Pyt ...

  9. Redis高可用解决方案:哨兵(Sentinel)

    哨兵是Redis的高可用解决方案:由多个哨兵组成的系统监视主从服务器,可以将下线的主服务器属下的某个从服 务器升级为新的主服务器,继续保障运行. 启动并初始化Sentinel redis-sentin ...

  10. shiro的使用与JWT整合

    一.shiro入门 两大框架对比:安全框架Shiro和SpringSecurity的比较 了解shiro 什么是Shiro Apache Shiro是一个Java的安全(权限)框架.| Shiro可以 ...