冲刺 CSP 联训模拟2
温馨提示
代码中的变量名可能与题意、题解不同。
代码不删缺省源,可以直接拿来对拍。
T1 挤压
Solution
众所周知,异或是一种按位运算,不好进行十进制的数间合并。我们考虑将每个数拆分为二进制的形式进行处理。
此时,对于每一种情况,假设表示
这相当于对于第
Optimise
考虑上面这个实现分讨的量很大,我们考虑将第
其中
Code
代码(峰值时间 ms 峰值内存 Mib 代码长度 Kib)
#include<bits/stdc++.h>
using namespace std;
const long long p=1000000007;
inline long long qpow(long long x,long long y){
long long rtr=1;
for(;y;y>>=1){
if(y&1) rtr=rtr*x%p;
x=x*x%p;
}
return rtr;
}
long long n,m,a[100100],tinv,ps[200100],ne[200100],dp[8][64][64],ans;
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%lld",&n);
tinv=qpow(1000000000,p-2);
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;++i){
scanf("%lld",&ps[i]);
ps[i]=ps[i]*tinv%p;
ne[i]=((1-ps[i])%p+p)%p;
}
for(int i=0;i<30;++i){
for(int j=0;j<30;++j){
dp[0][i][j]=1;
}
}
long long tb,tem[8];
for(int i=1;i<=n;++i){
for(int j=0;j<30;++j){
for(int k=j;k<30;++k){
tem[0]=dp[0][j][k];
tem[1]=dp[1][j][k];
tem[2]=dp[2][j][k];
tem[3]=dp[3][j][k];
tb=(((a[i]>>j)&1)<<1)|((a[i]>>k)&1);
for(int l=0;l<4;++l){
dp[l][j][k]=(tem[l]*ne[i]%p+tem[l^tb]*ps[i]%p)%p;
}
}
}
}
for(int i=0;i<30;++i){
for(int j=0;j<30;++j){
if(i^j) ans=(ans+(((1ll<<(i+j))%p*dp[3][i][j]%p)<<1)%p)%p;
else ans=(ans+(1ll<<(i+j))%p*dp[3][i][j]%p)%p;
}
}
printf("%lld",ans);
return 0;
}
T2 工地难题
Solution
假设不考虑
进行差分即可得到每个
对于
证明
考虑将
Code
代码(峰值时间 ms 峰值内存 Mib 代码长度 B)
#include<bits/stdc++.h>
using namespace std;
const long long p=1000000007;
long long n,m,t[400100],invt[400100],lans;
inline long long qpow(long long x,long long y){
long long rtr=1;
for(;y;y>>=1){
if(y&1) rtr=rtr*x%p;
x=x*x%p;
}
return rtr;
}
inline long long c(long long x,long long y){
if(x>y) return 0;
return t[y]*invt[x]%p*invt[y-x]%p;
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%lld%lld",&n,&m);
t[0]=invt[0]=1;
for(int i=1;i<=(n<<1);++i){
t[i]=i*t[i-1]%p;
}
invt[n<<1]=qpow(t[n<<1],p-2);
for(int i=(n<<1)-1;i;--i){
invt[i]=(i+1)*invt[i+1]%p;
}
for(int i=1;i<=m;++i){
long long ans=c(n-m,n);
for(int j=m-i-1,k=1;j>=0;j-=i+1,++k){
if(k&1) ans=((ans-c(n-m,j+n-m)*c(k,n-m+1)%p)%p+p)%p;
else ans=(ans+c(n-m,j+n-m)*c(k,n-m+1)%p)%p;
}
printf("%lld ",((ans-lans)%p+p)%p);
lans=ans;
}
return 0;
}
T3 星空遗迹
Solution
我们先考虑对“最终胜者”操作进行化简,可以发现以下性质:
- 对于
,只有前一个和后一个影响比较结果,如果后面大了前面所有的 也跟着变,所以 等价于 。 - 对于
,其中 能赢 ,在第一局必定为 , 表不确定。我们发现这个字符串只要最后一个字母是 就不会影响他与后面比较的结果,即 不变,所以 等价于只有一个 。
至此,我们将某个字母前面是该字母或它能赢的字母的情况进行了化简,得到一种稳定情况:某个字母前面是他赢不了的一个字母,反映到本题,则稳定的串一定为
- 若栈为空,则将
入栈。 - 若栈顶为
,加入 后依旧稳定,直接入栈。 - 若栈顶为
,因为栈是稳定结构要么只有 要么 前面有 ,只需弹出原来的 再入栈就稳定了。 - 若栈顶为
,因为栈是稳定结构要么只有 要么 前面有 ,只有 则清栈加 ,否则按照上文第二个性质去掉 并将 入栈。
容易发现,由于稳定结构每个字符都无法更新前一个字符,所以加入每个字符后“最终胜者”为此时栈顶字母。
以上操作放到本题复杂度为
- 存在栈的大小为
,则最后一次出现这种情况的时候进栈的元素即为栈底。 - 不存在这种情况,考虑忽略前面字符,最后一次栈最小时入栈元素要么是第一个进来没被消除,要么就是清空了栈,所以他就是栈底。
现在考虑与上文相对应的,
- 若栈为空,
。 - 若栈顶为
,直接入栈, 。 - 若栈顶为
,弹出 再入栈, 。 - 若栈顶为
,弹出 再入栈, 。
考虑对于
对于修改,我们考虑每次修改
Code
代码(峰值时间 ms 峰值内存 Mib 代码长度 Kib)
#include<bits/stdc++.h>
using namespace std;
struct node{
int data[800100],pos[800100],tag[800100];
inline void pushdown(int now){
if(tag[now]){
data[now<<1]+=tag[now];
tag[now<<1]+=tag[now];
data[now<<1|1]+=tag[now];
tag[now<<1|1]+=tag[now];
tag[now]=0;
}
}
void build(int now,int lft,int rgt,int* dt){
if(lft==rgt){
data[now]=dt[lft];
pos[now]=lft;
return;
}
pushdown(now);
int mid=(lft+rgt)>>1;
build(now<<1,lft,mid,dt);
build(now<<1|1,mid+1,rgt,dt);
if(data[now<<1]<data[now<<1|1]){
data[now]=data[now<<1];
pos[now]=pos[now<<1];
}else{
data[now]=data[now<<1|1];
pos[now]=pos[now<<1|1];
}
}
void add(int now,int lft,int rgt,int ll,int rr,int dt){
if(ll<=lft&&rgt<=rr){
data[now]+=dt;
tag[now]+=dt;
return;
}
pushdown(now);
int mid=(lft+rgt)>>1;
if(ll<=mid) add(now<<1,lft,mid,ll,rr,dt);
if(rr>mid) add(now<<1|1,mid+1,rgt,ll,rr,dt);
if(data[now<<1]<data[now<<1|1]){
data[now]=data[now<<1];
pos[now]=pos[now<<1];
}else{
data[now]=data[now<<1|1];
pos[now]=pos[now<<1|1];
}
}
pair<int,int> query(int now,int lft,int rgt,int ll,int rr){
if(ll<=lft&&rgt<=rr) return {data[now],pos[now]};
pushdown(now);
bool vis=0;
int mid=(lft+rgt)>>1;
pair<int,int> rtr,tem;
if(ll<=mid) rtr=query(now<<1,lft,mid,ll,rr),vis=1;
if(rr>mid){
tem=query(now<<1|1,mid+1,rgt,ll,rr);
if(vis&&rtr.first>tem.first) rtr=tem;
else rtr=tem;
}
return rtr;
}
}tree;
char a[200100];
int n,q,f[200100],s[200100];
inline int getv(char x){
if(x=='R') return 2;
if(x=='S') return 1;
return 0;
}
inline int cmp(char x,char y){
if(x==y) return 0;
x=getv(x),y=getv(y);
if((!x)&&y==2) return 1;
if(x==2&&(!y)) return -1;
if(x>y) return 1;
return -1;
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d%d %s ",&n,&q,a+1);
f[1]=s[1]=1;
for(int i=2;i<=n;++i){
f[i]=cmp(a[i-1],a[i]);
s[i]=f[i]+s[i-1];
}
tree.build(1,1,n,s);
char tc;
int ta,tb,td,tem;
for(;q;--q){
scanf("%d",&ta);
if(ta==1){
scanf("%d %c ",&tb,&tc);
a[tb]=tc;
if(tb^1){
tem=cmp(a[tb-1],a[tb]);
tree.add(1,1,n,tb,n,tem-f[tb]);
f[tb]=tem;
}
if(tb^n){
tem=cmp(a[tb],a[tb+1]);
tree.add(1,1,n,tb+1,n,tem-f[tb+1]);
f[tb+1]=tem;
}
}else{
scanf("%d%d",&tb,&td);
printf("%c\n",a[tree.query(1,1,n,tb,td).second]);
}
}
return 0;
}
T4 纽带
待更。
本文作者:Pursuing_OIer
本文链接:https://www.cnblogs.com/blog21012004/p/18447583
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步