2021.10.11考试总结[NOIP模拟74]
T1 自然数
发现\(mex\)是单调不降的,很自然地想到用线段树维护区间端点的贡献。
枚举左端点,用线段树维护每个右端点形成区间的\(mex\)值。每次左端点右移相当于删去一个数。
记\(a_i\)在\(i\)下一次出现的位置为\(pos_i\),那么左端点\(i\)移到\(i+1\),实际上就是将左端点在\([i,pos_i)\)的区间中\(mex\)值大于\(a_i\)的改为\(a_i\)。线段树上二分可以解决,中途要记区间最小值便于二分。
\(code:\)
T1
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace IO{
typedef long long LL;
auto read=[]()->int{
char ch=getchar(); int x=0,f=1;
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=[](LL x,int sp)->void{
char ch[20]; int len=0;
if(x<0){ x=~x+1; putchar('-'); }
do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
};
auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;
const int NN=200010;
int n,ans,tmp,a[NN];
vector<int>loc[NN];
bool bin[NN];
namespace segment_tree{
#define ld rt<<1
#define rd (rt<<1)|1
int sum[NN<<2],mnn[NN<<2],tag[NN<<2],len[NN<<2];
void pushup(int rt){
sum[rt]=sum[ld]+sum[rd];
mnn[rt]=min(mnn[ld],mnn[rd]);
}
void pushdown(int rt){
if(tag[rt]<0) return;
sum[ld]=tag[rt]*len[ld];
sum[rd]=tag[rt]*len[rd];
mnn[ld]=mnn[rd]=tag[rt];
tag[ld]=tag[rd]=tag[rt];
tag[rt]=-1;
}
void build(int rt,int l,int r){
len[rt]=r-l+1; tag[rt]=-1;
if(l==r) return;
int mid=l+r>>1;
build(ld,l,mid);
build(rd,mid+1,r);
}
void insert(int rt,int l,int r,int pos,int val){
if(l==r) return sum[rt]=mnn[rt]=val,void();
int mid=l+r>>1;
if(pos<=mid) insert(ld,l,mid,pos,val);
else insert(rd,mid+1,r,pos,val);
pushup(rt);
}
void modify(int rt,int l,int r,int opl,int opr,int val){
if(l==r){
if(mnn[rt]>val) mnn[rt]=sum[rt]=val;
return;
}
pushdown(rt);
int mid=l+r>>1;
if(l>=opl&&r<=opr){
if(mnn[rt]>=val){
mnn[rt]=tag[rt]=val;
sum[rt]=val*len[rt];
} else if(mnn[rd]>=val){
mnn[rd]=tag[rd]=val;
sum[rd]=val*len[rd];
modify(ld,l,mid,opl,opr,val);
pushup(rt);
} else modify(rd,mid+1,r,opl,opr,val),pushup(rt);
return;
}
if(opl<=mid) modify(ld,l,mid,opl,opr,val);
if(opr>mid) modify(rd,mid+1,r,opl,opr,val);
pushup(rt);
}
int query(int rt,int l,int r,int opl,int opr){
if(l>=opl&&r<=opr) return sum[rt];
pushdown(rt);
int mid=l+r>>1,res=0;
if(opl<=mid) res+=query(ld,l,mid,opl,opr);
if(opr>mid) res+=query(rd,mid+1,r,opl,opr);
return res;
}
} using namespace segment_tree;
signed main(){
freopen("mex.in","r",stdin);
freopen("mex.out","w",stdout);
n=read(); build(1,1,n);
for(int i=1;i<=n;i++){
a[i]=read();
if(a[i]<=n)
loc[a[i]].push_back(i), bin[a[i]]=1;
while(bin[tmp]) ++tmp;
insert(1,1,n,i,tmp);
}
for(int i=0;i<=n;i++)
if(loc[i].size())
loc[i].push_back(n+1);
for(int i=1;i<=n;i++){
ans+=query(1,1,n,i,n);
if(a[i]>n) continue;
int pos=*upper_bound(loc[a[i]].begin(),loc[a[i]].end(),i);
modify(1,1,n,i,pos-1,a[i]);
}
return write(ans,'\n'),0;
}
T2 钱仓
对于正整数\(a,b\),\(a^2+b^2<(a+b)^2\)。于是有贪心:断环为链后从后往前扫,每次遇到有东西的仓库,就把东西移到最靠后的位置。
发现不管怎么贪心,最后都是最优解。于是找到一个合法端点贪心一遍即可。
\(code:\)
T2
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace IO{
auto read=[]()->int{
char ch=getchar(); int x=0,f=1;
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,int sp)->void{
char ch[20]; int len=0;
if(x<0){ x=~x+1; putchar('-'); }
do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
};
auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;
const int NN=100010;
int n,s,mx,pre,res,c[NN<<1],o[NN];
int calc(int x){ return x*(x+1)*(2*x+1)/6; }
signed main(){
freopen("barn.in","r",stdin);
freopen("barn.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) c[i]=c[i+n]=read();
for(int i=1;i<=n;i++){
pre+=c[i]-1;
if(pre<0) s=i+1,pre=0;
} pre=0;
for(int i=s+n-1;i>=s;i--){
if(!c[i]){ if(!pre) pre=i; }
else if(pre) res+=calc(pre-i)-calc(pre-i-c[i]),pre-=c[i];
}
return write(res,'\n'),0;
}
/*
10
1
0
0
2
0
0
1
2
2
2
*/
T3 游戏
令\(Alice\)为\(A\),\(Bob\)为\(B\),设\(a_n\),\(b_n\)分别为\(A\),\(B\)在剩\(n\)个石子时先手,\(A\)的胜率。
一些结论:
- 若A先手,A认为现在想投某一面更优,那么在当前这个石子被某一个人拿走之前她会一直想投这一面,B先手时对于B也是如此
- 若A先手,为了阻止A投到某一面,B也要选择投这一面,也就是说对于任意一个石子,A和B的决策相同
不难推出转移式子:
若\(a_n\geq b_n\):
\]
\]
同理,
\]
\]
\(a_n\leq b_n\)时类似,
\]
\]

实际上就是\(n\)为奇数时用第一种转移,为偶数时用第二种转移。将奇偶转移合为一次转移,矩阵优化。
\(code:\)
T3
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace IO{
auto read=[]()->int{
char ch=getchar(); int x=0,f=1;
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,int sp)->void{
char ch[20]; int len=0;
if(x<0){ x=~x+1; putchar('-'); }
do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
};
auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;
const int mod=1e9+7;
int T,n,p,q;
int qpow(int a,int b){
int res=1; a%=mod;
for(;b;b>>=1){
if(b&1) res=res*a%mod;
a=a*a%mod;
}
return res;
}
const int inv=qpow(100000000,mod-2),inv3=qpow(3,mod-2);
namespace Matrix{
struct mat{
int s[3][3];
mat(){}
mat(int x){ memset(s,0,sizeof(s)); s[1][1]=s[2][2]=x; }
mat operator*(const mat& a)const{
mat res=mat(0);
for(int i=1;i<3;i++)
for(int k=1;k<3;k++)
for(int j=1;j<3;j++)
(res.s[i][j]+=s[i][k]*a.s[k][j])%=mod;
return res;
}
}s,t,t1,t2;
mat operator^(mat a,int b){
mat res=mat(1);
for(;b;b>>=1){
if(b&1) res=res*a;
a=a*a;
}
return res;
}
void prework(){
s.s[1][2]=1; s.s[1][1]=0;
t1.s[1][1]=(mod+1-p)*q%mod*qpow(mod+p+q-p*q%mod,mod-2)%mod;
t1.s[2][1]=p*qpow(mod+p+q-p*q%mod,mod-2)%mod;
t1.s[1][2]=q*qpow(mod+p+q-p*q%mod,mod-2)%mod;
t1.s[2][2]=(mod+1-q)*p%mod*qpow(mod+p+q-p*q%mod,mod-2)%mod;
t2.s[1][1]=p*(mod+1-q)%mod*qpow(mod+1-p*q%mod,mod-2)%mod;
t2.s[2][1]=(mod+1-p)*qpow(mod+1-p*q%mod,mod-2)%mod;
t2.s[1][2]=(mod+1-q)*qpow(mod+1-p*q%mod,mod-2)%mod;
t2.s[2][2]=q*(mod+1-p)%mod*qpow(mod+1-p*q%mod,mod-2)%mod;
t=t1*t2;
}
} using namespace Matrix;
signed main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
T=read();
while(T--){
n=read(); p=read(); q=read();
p=p*inv%mod; q=q*inv%mod;
prework();
t=t^(n/2); s=s*t;
if(n&1) s=s*t1;
write(s.s[1][1],'\n');
}
return 0;
}
2021.10.11考试总结[NOIP模拟74]的更多相关文章
- 2021.8.11考试总结[NOIP模拟36]
T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...
- 2021.10.7考试总结[NOIP模拟71]
信心赛,但炸了.T3SB错直接炸飞,T4可以硬算的组合数非要分段打表求阶乘..T2也因为一个细节浪费了大量时间.. 会做难题很好,但首先还是要先把能拿的分都拿到. T1 签到题 结论:总可以做到对每个 ...
- 2021.10.15考试总结[NOIP模拟77]
\(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...
- 2021.10.18考试总结[NOIP模拟76]
T1 洛希极限 不难发现每个点肯定是被它上一行或上一列的点转移.可以预处理出每个点上一行,上一列最远的能转移到它的点,然后单调队列优化. 预处理稍显ex.可以用并查集维护一个链表,记录当前点之后第一个 ...
- 2021.10.12考试总结[NOIP模拟75]
T1 如何优雅的送分 考虑式子的实际意义.\(2^{f_n}\)实际上就是枚举\(n\)质因子的子集.令\(k\)为这个子集中数的乘积,就可以将式子转化为枚举\(k\),计算\(k\)的贡献. 不难得 ...
- 2021.10.9考试总结[NOIP模拟72]
T1出了个大阴间题 状压\(DP\),记当前状态的代价和与方案数.状态\(\Theta(2^nn)\),转移\(\Theta(n)\). 发现每个状态的最大值只会是所选集合的\(max\)或加一.于是 ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- 2021.9.13考试总结[NOIP模拟52]
T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...
- 2021.9.14考试总结[NOIP模拟53]
T1 ZYB和售货机 容易发现把每个物品都买成$1$是没有影响的. 然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以 ...
随机推荐
- 关于软链接ln -s 的使用
1.效果跟windows创建快捷方式是一样的,先找到要被创建的原始文件或目录.然后才能创建. 2.格式:ln -s [源文件或目录] [目标文件或目录] 3.源文件或目录必须是绝对目录. 4 ...
- python win32com 处理excle 写一个公共的类
利用win32com处理excle,这样可以不管文件是老的xls还是新的xlsx格式,非常方便. 类的源码如下: import win32com.client as win32 class easyE ...
- 边缘使用 K8s 门槛太高?OpenYurt 这个功能帮你快速搭建集群!
OpenYurt作为阿里巴巴首个开源的边缘云原生项目,涉及到边缘计算和云原生两个领域.然而,许多边缘计算的开发者并不熟悉云原生相关的知识.为了降低 OpenYurt 的使用门槛,帮助更多地开发者快速上 ...
- 【Linux】LNMP1.6 环境报500错误解决方法
vi /usr/local/nginx/conf/fastcgi.conf 进入编辑fastcgi.conf 找到 fastcgi_param PHP_VALUE "open_base ...
- 什么是云效 Projex,云效Projex企业级高效研发项目管理平台
云效项目协作Projects是一款企业级高效研发项目管理平台, 提供了快速实践的敏捷研发项目管理机制,提供对需求.迭代.缺陷各个维度的协同管理以及相关的统计报告,让研发团队高效协作.践行敏捷并持续交付 ...
- Java基础系列(11)- 变量、常量、作用域以及变量的命名规范
变量 变量是什么:就是可以变化的量 Java是一种强类型语言,每个变量都必须声明其类型 Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域 type varName [=valu ...
- Influxdb数据库 - 基本操作
InfluxDB数据库的简介 InfluxDB是一个用于存储和分析时间序列数据的开源数据库,是一个基于 golang 编写,用于记录 metrics.events,进行数据分析. 主要特性有: 内置H ...
- xmind使用技巧
xmind看似每个人都会使用,但是掌握一些小技巧,能够有效提升工作效率. 多行复制粘贴 在xmind中选中多行,复制然后可以直接粘贴到excel.word当中. 在excel.word选中多行,复制然 ...
- test,exec,match,replace方法区别 正则
这四种方法都是用来检测字符串是否包含某一子串或是否匹配否个正则表达式 test方法,匹配返回true,不匹配返回false match,匹配返回匹配到的数组(包含多次/g),匹配一次返回包含匹配子串的 ...
- netty系列之:使用netty搭建websocket服务器
目录 简介 netty中的websocket websocket的版本 FrameDecoder和FrameEncoder WebSocketServerHandshaker WebSocketFra ...