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. liquibase新增字段注释导致表格注释同时变更bug记录

    liquibase是一个用于数据库变更跟踪.版本管理和自动部署的开源工具.它的使用方式方法可以参考官方文档或者其他人的博客,这里不做过多介绍. 1. 问题复现 在使用过程中发现了一个版本bug.这个b ...

  2. MapReduce 示例:减少 Hadoop MapReduce 中的侧连接

    摘要:在排序和reducer 阶段,reduce 侧连接过程会产生巨大的网络I/O 流量,在这个阶段,相同键的值被聚集在一起. 本文分享自华为云社区<MapReduce 示例:减少 Hadoop ...

  3. 内部类访问外部类成员变量,使用外部类名.this.成员变量

    public class Outer { private int age = 12; class Inner { private int age = 13; public void print() { ...

  4. PHP中操作任意精度大小的GMP扩展学习

    对于各类开发语言来说,整数都有一个最大的位数,如果超过位数就无法显示或者操作了.其实,这也是一种精度越界之后产生的精度丢失问题.在我们的 PHP 代码中,最大的整数非常大,我们可以通过 PHP_INT ...

  5. Jmeter系列(22)- 常用逻辑控制器(1) | 随机控制器Random Controller

    随机控制器(Random Controller) 该控制器下的请求,请求顺序随机,适用场景一般为顺序性依赖不强的请求,比如:下载文件:浏览商品:访问查询接口 随机控制器下的请求随机,如果勾选了[忽略控 ...

  6. Shell系列(4)- 历史命令

    格式:history [选项] [历史命令保存文件] 选项: -c:清空历史命令 -w:把缓存中的历史命令写入到历史命令保存文件~ /.bash_history;用户的家目录下 例子: [root@l ...

  7. Shell系列(10)- bash环境变量(3)

    环境变量与用户自定义变量的区别 环境变量是全局变量,用户自定义变量是局部变量. 用户自定义变量只在当前的 shell 中生效,环境变量在当前 shell 和这个 shell 的所有子 shell 中生 ...

  8. Linux文件(夹)属性与权限

    文件属性与权限,文件权限设置 参考资料:鸟哥的Linux私房菜 用户与用户组 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这 ...

  9. Redis之品鉴之旅(二)

    2)hash类型,上代码 using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345&qu ...

  10. 关于java实体类时间类型的格式化调整问题

    关于java bean在后台\转化为json交给前台时间类型格式调整的方法: 首先要引入fastjson依赖. 在实体类上使用注解: @JsonFormat(pattern = "yyyy- ...