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+1}=(1-p)\times b_n+p\times(1-q)\times a_n+p\times q\times a_{n+1}
\]
\[a_{n+1}=\frac{p\times(1-q)\times a_n+(1-p)\times b_n}{1-p\times q}
\]

同理,

\[b_{n+1}=(1-q)\times a_n+q\times(1-p)\times b_n+p\times q\times b_{n+1}
\]
\[b_{n+1}=\frac{(1-q)\times a_n+q\times(1-p)\times b_n}{q-p\times q}
\]

\(a_n\leq b_n\)时类似,

\[a_{n+1}=\frac{q\times(1-p)\times a_n+p\times b_n}{p+q-p\times q}
\]
\[b_{n+1}=\frac{q\times a_n+p\times(1-q)\times b_n}{p+q-p\times q}
\]

实际上就是\(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]的更多相关文章

  1. 2021.8.11考试总结[NOIP模拟36]

    T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...

  2. 2021.10.7考试总结[NOIP模拟71]

    信心赛,但炸了.T3SB错直接炸飞,T4可以硬算的组合数非要分段打表求阶乘..T2也因为一个细节浪费了大量时间.. 会做难题很好,但首先还是要先把能拿的分都拿到. T1 签到题 结论:总可以做到对每个 ...

  3. 2021.10.15考试总结[NOIP模拟77]

    \(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...

  4. 2021.10.18考试总结[NOIP模拟76]

    T1 洛希极限 不难发现每个点肯定是被它上一行或上一列的点转移.可以预处理出每个点上一行,上一列最远的能转移到它的点,然后单调队列优化. 预处理稍显ex.可以用并查集维护一个链表,记录当前点之后第一个 ...

  5. 2021.10.12考试总结[NOIP模拟75]

    T1 如何优雅的送分 考虑式子的实际意义.\(2^{f_n}\)实际上就是枚举\(n\)质因子的子集.令\(k\)为这个子集中数的乘积,就可以将式子转化为枚举\(k\),计算\(k\)的贡献. 不难得 ...

  6. 2021.10.9考试总结[NOIP模拟72]

    T1出了个大阴间题 状压\(DP\),记当前状态的代价和与方案数.状态\(\Theta(2^nn)\),转移\(\Theta(n)\). 发现每个状态的最大值只会是所选集合的\(max\)或加一.于是 ...

  7. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  8. 2021.9.13考试总结[NOIP模拟52]

    T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...

  9. 2021.9.14考试总结[NOIP模拟53]

    T1 ZYB和售货机 容易发现把每个物品都买成$1$是没有影响的. 然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以 ...

随机推荐

  1. 生成随机uuid

      /**  * 生成随机uuid  */ export function uuid() {   return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.repla ...

  2. 远程桌面连接(mstsc)全攻略

    打算从今天开始,写一写我经常用的,有长时间使用经验的东西,与大家分享,就从mstsc开始吧! mstsc应该是在Windows中,除了calc.cmd.notepad.mspaint,我使用率最高的系 ...

  3. PTA 面向对象程序设计 6-1 引用作函数形参交换两个整数

    引用作函数形参交换两个整数 设计一个void类型的函数Swap,该函数有两个引用类型的参数,函数功能为实现两个整数交换的操作. 裁判测试程序样例: #include <iostream> ...

  4. Java多线程-1(3)

    本份随记主要为狂神老师的Java多线程教学的学习笔记,记载了视频中一些有关基础概念以及部分代码示例.随机分为1-3共三份,知识点记录的不是很深入,以后的学习过程中随时补充. 1 有关基础概念 1.1 ...

  5. Docker DevOps实战:Docker+Jenkins+Python+Pytest+Allure(1)- 创建Jenkins容器、安装Python环境、安装项目依赖类库、安装Allure报告插件

    前言: 本文实操笔记参照菠萝笔记,安装过程中的坑大家可以参考下 创建Jenkins容器 # 下载Jenkins镜像 [root@localhost ~]# docker pull jenkins/je ...

  6. windows日志查看与清理

    日志查看 (1) 启动Windows实验台,点击:开始 - 控制面板 - 管理工具 - 事件查看器. (2) 应用程序日志.安全日志.系统日志.DNS日志默认位置:%sys temroot%\syst ...

  7. jmeter监控linux服务器资源

    https://blog.csdn.net/weixin_38102592/article/details/100136375 https://blog.csdn.net/liuqiuxiu/arti ...

  8. appium+python自动化:获取元素属性get_attribute

    使用get_attribute()获取元素属性,括号里应该填写什么? 查看appium源码 如果是获取resource-id,填写resourceId self.driver.find_element ...

  9. AOJ/搜索与递归及分治法习题集

    ALDS1_4_A-LinearSearch. Description: You are given a sequence of n integers S and a sequence of diff ...

  10. 初探计算机网络之CPU和内存

    CPU ​ CPU是一块超大规模的集成电路板,是计算机的核心部件,承载着计算机的主要运算和控制功能,是计算机的最终解释模块和执行模块.总之,用一句话概括就是,CPU是由控制器和运算器组成的,而内部寄存 ...