Noip模拟74 2021.10.11
T1 自然数
考场上当我发现我的做法可能要打线段树的时候,以为自己百分之百是考虑麻烦了
但还是打了,还过掉了所有的样例,于是十分自信的就交了
正解还真是线段树,真就第一题数据结构
但是包括自己造的小样例还是大样例我都少考虑了一个问题,就是元素可能相等
所以估分$100$实际只有$68$,以后造样例的时候还是要根据题目搞一些极端的数据出来
先说暴力吧,考虑到$a_i$的值域是拿来吓唬人的,因为$mex$不可能超过$2e5$
所以大于边界的值直接跳过不考虑,这个条件比较关键
那么我们使用经典指针
$pos$指向答案,初始指向$0$,枚举左端点扫右端点
那么每次使用栈记录遍历到的$a_i$值,以便清空时更快
显然只有当扫到的点的值把当前$pos$的位置占了之后$pos$才会移动
所以维护指针的算法就出来了,$O(n^2)$
1 for(int l=1;l<=n;l++){ 2 int pos=0,r=l; 3 while(vis[pos]) ++pos; 4 while(r<=n){ 5 if(a[r]<NN&&(!vis[a[r]])) vis[a[r]]=1,stk[++top]=a[r]; 6 while(vis[pos]) ++pos; 7 ++r; ans+=pos; 8 } 9 while(top) vis[stk[top--]]=0; 10 } 11 write(ans);
那么考虑优化右端点移动的过程
先把$1~[1,N]$的所有区间的贡献预处理出来,用一个数组记录,为$h[r]$
拿我自己造的优秀$hack$数据举例
5 1 2 0 3 5 //其实还有 5 2 1 0 3 5 && 5 3 1 0 2 5
以上三个答案分别是$17,20,21$
以第二个来说的话,预处理出的数组为$0,0,3,4,4$,
然后考虑每次删除一个左端点,发现贡献会依次变为
$0,2,2,2$、$1,1,1$、$0,0$、$0$,然后你可以再试一下有重复数字的数组
发现$a[l]$(当前要删的左端点值)会把第一个大于它的数($h$数组里的)到下一个它出现($a$数组里的)之间的所有数覆盖成$a[l]$这个值
想一想的话也很好理解(基于你打了双指针移动的暴力)
所以你记录一个$nxt$数组,线段树上维护一个$sum,minn$就可以解决问题了,找位置用线段树二分
因为我是没发现有重复,所以直接更新到$n$他是对的,于是我直接在没修改的$h$数组上面二分找位置也是对的,
因为每次更新只会往小里更新,而且更新之后数组还是单调不降。
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 const int NN=400005; 15 int n,a[NN],ans,sum,h[NN],nxt[NN]; 16 int vis[NN],tag[NN]; 17 struct SNOWtree{ 18 #define lid (id<<1) 19 #define rid (id<<1|1) 20 int ll[NN<<2],rr[NN<<2]; 21 int sum[NN<<2],laz[NN<<2],mn[NN<<2]; 22 inline void pushup(int id){ 23 if(ll[id]==rr[id]) return; 24 sum[id]=sum[lid]+sum[rid]; 25 mn[id]=min(mn[lid],mn[rid]); 26 } 27 inline void pushdown(int id){ 28 if(ll[id]==rr[id]||laz[id]==-1) return; 29 laz[lid]=laz[rid]=laz[id]; 30 mn[rid]=mn[lid]=laz[id]; 31 sum[lid]=laz[id]*(rr[lid]-ll[lid]+1); 32 sum[rid]=laz[id]*(rr[rid]-ll[rid]+1); 33 laz[id]=-1; 34 } 35 inline void build(int id,int l,int r){ 36 ll[id]=l; rr[id]=r; laz[id]=-1; mn[id]=0x3fffffff; 37 if(l==r) return mn[id]=sum[id]=h[l],void(); 38 int mid=l+r>>1; 39 build(lid,l,mid); build(rid,mid+1,r); 40 pushup(id); 41 } 42 inline void change(int id,int pos,int v){ 43 if(ll[id]==rr[id]) return mn[id]=sum[id]=v,void(); 44 pushdown(id);int mid=ll[id]+rr[id]>>1; 45 if(pos<=mid) change(lid,pos,v); 46 else change(rid,pos,v); 47 pushup(id); 48 } 49 inline void update(int id,int l,int r,int v){ 50 if(l<=ll[id]&&rr[id]<=r){ 51 sum[id]=v*(rr[id]-ll[id]+1); 52 mn[id]=laz[id]=v; return; 53 }pushdown(id);int mid=ll[id]+rr[id]>>1; 54 if(l<=mid) update(lid,l,r,v); 55 if(r>mid) update(rid,l,r,v); 56 pushup(id); 57 } 58 inline int lower_bound_(int id,int pos){ 59 if(ll[id]==rr[id]){ 60 if(mn[id]>=pos) return ll[id]; 61 return n+1; 62 }pushdown(id); 63 if(mn[rid]<pos) return lower_bound_(rid,pos); 64 else return min(lower_bound_(lid,pos),ll[rid]); 65 return n+1; 66 } 67 }tr; 68 namespace WSN{ 69 inline short main(){ 70 // freopen("in.in","r",stdin); 71 // freopen("bao.out","w",stdout); 72 freopen("mex.in","r",stdin); 73 freopen("mex.out","w",stdout); 74 n=read(); 75 for(int i=1;i<=n;i++) a[i]=read(); 76 int pos=0; 77 for(int r=1;r<=n;r++){ 78 if(a[r]<NN&&(!vis[a[r]])) vis[a[r]]=1; 79 while(vis[pos]) ++pos; 80 sum+=pos; h[r]=pos; nxt[r]=n+1; 81 } 82 memset(vis,0,sizeof(vis)); 83 for(int i=1;i<=n;i++) if(a[i]<NN) nxt[vis[a[i]]]=i,vis[a[i]]=i; 84 // for(int i=1;i<=n;i++) cout<<nxt[i]<<" ";cout<<endl; 85 // cout<<sum<<endl; 86 ans=sum; tr.build(1,1,n); 87 for(int l=1;l<n;l++){ 88 tr.change(1,l,0); 89 pos=tr.lower_bound_(1,a[l]+1); 90 // cout<<pos<<" "<<nxt[pos]<<endl; 91 if(pos<nxt[l]) tr.update(1,pos,nxt[l]-1,a[l]); 92 ans+=tr.sum[1]; 93 } 94 write(ans); 95 return 0; 96 } 97 } 98 signed main(){return WSN::main();} 99 // cout<<a[l-1]<<" "<<pos<<" "<<tr.query(1,l,pos-1)<<" "<<(n-pos+1)*a[l-1]<<endl;
T2 钱仓
按照$c_i-1$的前缀和找到最长的$\geq 0$的一段,记一个起点$S$然后倒着贪心把有东西的点上的东西能向后移动就向后移动
维护一个队列就行
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 const int NN=2e5+5; 15 int n,c[NN],S,sum; 16 int q[NN],l,r; 17 namespace WSN{ 18 inline short main(){ 19 // freopen("in.in","r",stdin); 20 // freopen("bao.out","w",stdout); 21 freopen("barn.in","r",stdin); 22 freopen("barn.out","w",stdout); 23 n=read(); 24 for(int i=1;i<=n;i++) c[n+i]=c[i]=read(); 25 for(int i=1;i<=n;i++){ 26 sum+=c[i]-1; 27 if(sum<0) S=i+1,sum=0; 28 } 29 l=1,r=sum=0; 30 for(int i=S+n-1;i>=S;i--){ 31 if(!c[i]) q[++r]=i; 32 else{ 33 while(l<=r && c[i]){ 34 int pos=q[l++]; --c[i]; 35 sum+=(pos-i)*(pos-i); 36 } 37 if(!c[i]) q[++r]=i; 38 } 39 } write(sum); 40 return 0; 41 } 42 } 43 signed main(){return WSN::main();}
T3 游戏
设$a_n,b_n$分别为剩下$n$个石子时$A$先手获胜的概率和$B$先手获胜的概率
发现$n$为奇数的时候两人都想拿,偶数时都不想
那么有两个递推方程
$a_{n+1}=p(1-q)a_n+(1-p)b_n+(1-p)(1-q)a_{n+1}$
$b_{n+1}=q(1-p)b_n+(1-q)a_n+(1-p)(1-q)b_{n+1}$
然后化简按照奇数偶数转移就有$76$分
然后把转移系数构建矩阵就可以了
具体就是把奇数矩阵先和偶数矩阵乘在一起,然后做$\frac{n}{2}$次转移
如果$n$是奇数再来一次奇数矩阵,
最后直接输出第二行第一列的值即可,因为$a_0=0,b_0=1$,转移只有那一个有贡献
复杂度$O(8log_nT)$
1 #include<stdio.h> 2 #include<algorithm> 3 #include<cstring> 4 #define int long long 5 using namespace std; 6 const int mod=1e9+7,inv=571428574; 7 int T,n,p,q; 8 inline int qmo(int a,int b,int ans=1){ 9 int c=mod;for(;b;b>>=1,a=a*a%c)if(b&1)ans=ans*a%c; 10 return ans; 11 } 12 namespace Matrix{ 13 struct Ma{ 14 int m[3][3]; 15 Ma(){memset(m,0,sizeof(m));} 16 inline void pre(){m[1][1]=m[2][2]=1;} 17 inline void print(){printf("%lld %lld\n%lld %lld\n",m[1][1],m[1][2],m[2][1],m[2][2]);} 18 Ma operator*(const Ma&a)const{ 19 Ma res; 20 for(int i=1;i<=2;i++) 21 for(int j=1;j<=2;j++) 22 for(int k=1;k<=2;k++) 23 (res.m[i][j]+=m[i][k]*a.m[k][j]%mod)%=mod; 24 return res; 25 } 26 }; 27 inline Ma ksm(Ma a,int b){ 28 Ma ans;ans.pre(); 29 for(;b;b>>=1,a=a*a)if(b&1)ans=ans*a; 30 return ans; 31 } 32 int c[3]; 33 inline void mul(int a[3],Ma b){ 34 memset(c,0,sizeof(c)); 35 for(int i=1;i<=2;i++) 36 for(int j=1;j<=2;j++) 37 (c[i]+=a[j]*b.m[j][i]%mod)%=mod; 38 memcpy(a,c,sizeof(c)); 39 } 40 }using namespace Matrix; 41 namespace TASK{ 42 inline void task1(){ 43 int P=p*inv%mod,Q=q*inv%mod; 44 printf("%lld\n",P*qmo((1-((1-P+mod)%mod)*((1-Q+mod)%mod)%mod+mod)%mod,mod-2)%mod); 45 } 46 inline void task2(){ 47 int P=p*inv%mod,Q=q*inv%mod,v3=qmo(3,mod-2);Ma g; 48 g.m[2][2]=g.m[1][1]=v3;g.m[2][1]=g.m[1][2]=2*v3%mod; 49 g=ksm(g,n);printf("%lld\n",g.m[2][1]); 50 } 51 int a[1005],b[1005]; 52 inline void task3(){ 53 memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); 54 a[0]=0; b[0]=1; 55 int P=p*inv%mod,Q=q*inv%mod; 56 for(int i=1;i<=n;i++){ 57 if((i&1)==0){ 58 int tmp=qmo((1-P*Q%mod+mod)%mod,mod-2); 59 a[i]=P*((1-Q+mod)%mod)%mod*tmp%mod*a[i-1]%mod+(1-P+mod)%mod*tmp%mod*b[i-1]%mod; 60 b[i]=(1-Q+mod)%mod*tmp%mod*a[i-1]%mod+Q*((1-P+mod)%mod)%mod*tmp%mod*b[i-1]%mod; 61 }else{ 62 int tmp=qmo((1-((1-P+mod)%mod)*((1-Q+mod)%mod)%mod+mod)%mod,mod-2); 63 a[i]=(1-P+mod)%mod*Q%mod*tmp%mod*a[i-1]%mod+P*tmp%mod*b[i-1]%mod; 64 b[i]=Q*tmp%mod*a[i-1]%mod+(1-Q+mod)%mod*P%mod*tmp%mod*b[i-1]%mod; 65 } 66 } 67 printf("%lld\n",a[n]%mod); 68 } 69 }using namespace TASK; 70 int dp[3]; 71 namespace WSN{ 72 inline short main(){ 73 freopen("game.in","r",stdin); 74 freopen("game.out","w",stdout); 75 scanf("%lld",&T); 76 while(T--){ 77 scanf("%lld%lld%lld",&n,&p,&q); 78 Ma f,g; 79 int P=p*inv%mod,Q=q*inv%mod; 80 int tmp=qmo((1-P*Q%mod+mod)%mod,mod-2); 81 f.m[1][1]=P*((1-Q+mod)%mod)%mod*tmp%mod; 82 f.m[1][2]=(1-Q+mod)%mod*tmp%mod; 83 f.m[2][1]=(1-P+mod)%mod*tmp%mod; 84 f.m[2][2]=Q*((1-P+mod)%mod)%mod*tmp%mod; 85 tmp=qmo((1-((1-P+mod)%mod)*((1-Q+mod)%mod)%mod+mod)%mod,mod-2); 86 g.m[1][1]=(1-P+mod)%mod*Q%mod*tmp%mod; 87 g.m[1][2]=Q*tmp%mod; 88 g.m[2][1]=P*tmp%mod; 89 g.m[2][2]=(1-Q+mod)%mod*P%mod*tmp%mod; 90 Ma ret=g*f; int b=n/2;dp[1]=0;dp[2]=1; 91 while(b){ 92 if(b&1) mul(dp,ret); 93 b>>=1; ret=ret*ret; 94 } 95 if(n&1) mul(dp,g); 96 printf("%lld\n",dp[1]%mod); 97 } 98 return 0; 99 } 100 } 101 signed main(){return WSN::main();}
T4 Sanrd
咕咕咕