4.1 模拟赛
T1 luogu 5249
题目大意:
有$n$个人按顺序坐成一圈玩游戏,从$1$号开始每次抛硬币,如果是正面就出局,无论结果如何都把硬币给下一个没出局的人
这个硬币概率是正面的概率为$p$由一个分数$\frac{a}{b}$的形式给出$a,b$,问$1-n$号人留到最后的概率在$\mod 998244353$下的数
思路:
设$f_{i,j}$表示总共还剩$i$个人的时候,若当前抛硬币的人编号为$1$,编号为$j$的人作为最后一个人的概率
则容易推出方程$f_{i,j}=p*f_{i-1,j-1}+q*f_{i,j-1}$,由于是环形所以需要消元
因为对每个$i$,需要所有$i-1$都已知才可以,这样我们一行一行使用高斯消元复杂度为$n^4$
考虑手动推系数,把一行内所有的$f_{i,j}$全部用$f_{i,1}$代替
推出$f_{i,1}$的系数和其余常数项,因为每一行的和都是$1$,算出$f_{i,1}$之后再带回去即可,复杂度$n^2$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MOD 998244353 15 #define MAXN 5010 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define mem(x,i) memset(x,i,sizeof(x)) 20 #define pb(i,x) vec[i].push_back(x) 21 #define pls(a,b) (a+b)%MOD 22 #define mns(a,b) (a-b+MOD)%MOD 23 #define mul(a,b) (1LL*(a)*(b))%MOD 24 using namespace std; 25 inline int read() 26 { 27 int x=0,f=1;char ch=getchar(); 28 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 29 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 30 return x*f; 31 } 32 int n,f[MAXN][MAXN],p,q,sum,k,tmp,s; 33 int q_pow(int bas,int t,int res=1) 34 { 35 for(;t;t>>=1,bas=mul(bas,bas)) 36 if(t&1) res=mul(res,bas);return res; 37 } 38 #define inv(x) q_pow(x,MOD-2) 39 int main() 40 { 41 freopen("A.in","r",stdin);freopen("A.out","w",stdout); 42 int a=read(),b=read();n=read();p=mul(inv(b),a),q=mns(1,p); 43 f[1][1]=1;rep(i,2,n) 44 { 45 s=sum=0,k=tmp=1;rep(j,2,i) tmp=mul(tmp,q),k=pls(k,tmp), 46 s=pls(mul(s,q),mul(p,f[i-1][j-1])),sum=pls(sum,s); 47 f[i][1]=mul(mns(1,sum),inv(k));rep(j,2,i) 48 f[i][j]=pls(mul(p,f[i-1][j-1]),mul(q,f[i][j-1])); 49 } 50 rep(i,1,n) printf("%d ",f[n][i]); 51 }
T2
题目大意:
有一个长度为$n$的字符串,字符集为$n$
$Q$组询问,形如$l,r$,询问删除一个左端点$\leq l$,右端点$\geq r$的子串后,剩下的部分可以形成的不同串的数量
思路:
有一个可以感性理解的结论为 $ans=$所有子串数量减去两边每种字符的数量乘积之和
然后使用莫队,维护左右两边的数量即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 100100 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) tot[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 int n,m,g[MAXN],bl[MAXN],lnum[MAXN],rnum[MAXN],sz; 31 ll ans[MAXN],res;struct ask{int l,r,t,id;}q[MAXN]; 32 bool cmp(ask a,ask b){return bl[a.l]<bl[b.l]||(bl[a.l]==bl[b.l]&&a.r<b.r);} 33 int main() 34 { 35 freopen("B.in","r",stdin);freopen("B.out","w",stdout); 36 n=read(),sz=sqrt(n);rep(i,1,n) g[i]=read(),bl[i]=(i-1)/sz;g[n+1]=n+1; 37 m=read();rep(i,1,m) q[i].l=read()-1,q[i].r=read()+1,q[i].id=i; 38 sort(q+1,q+m+1,cmp);int l=0,r=n+1;rep(i,1,m) 39 { 40 while(l<q[i].l) {l++;res+=rnum[g[l]],lnum[g[l]]++;} 41 while(l>q[i].l) {res-=rnum[g[l]],lnum[g[l]]--;l--;} 42 while(r>q[i].r) {r--;res+=lnum[g[r]],rnum[g[r]]++;} 43 while(r<q[i].r) {res-=lnum[g[r]],rnum[g[r]]--;r++;} 44 ans[q[i].id]=1LL*(q[i].l+1)*(n-q[i].r+2)-res; 45 }rep(i,1,m) printf("%lld\n",ans[i]); 46 }
有结论之后的B题是bzoj 5016这道题的弱化版
题意为:给定了两个区间$[l1,r1]$和$[l2,r2]$,求$\sum\limits_{i=0}^{\infty} get(l1,r1,i)\times get(l2,r2,i)$,其中$get(l,r,x)$表示$[l,r]$中$x$的数量
思路:还是莫队,拆成四个区间容斥一下即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 200100 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) tot[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 int n,m,g[MAXN],bl[MAXN],lnum[MAXN],rnum[MAXN],sz; 31 ll ans[MAXN],res;struct ask{int l,r,t,id;}q[MAXN]; 32 bool cmp(ask a,ask b){return bl[a.l]<bl[b.l]||(bl[a.l]==bl[b.l]&&a.r<b.r);} 33 int main() 34 { 35 n=read(),sz=sqrt(n);rep(i,1,n) g[i]=read(),bl[i]=(i-1)/sz;g[n+1]=n+1; 36 m=read();int l,r,x,y;rep(i,1,m) 37 { 38 l=read(),r=read(),x=read(),y=read(); 39 q[(i-1<<2)|1]=(ask){r,x,1,i}; 40 q[(i-1<<2)|2]=(ask){l-1,x,-1,i}; 41 q[(i-1<<2)|3]=(ask){r,y+1,-1,i}; 42 q[i<<2]=(ask){l-1,y+1,1,i}; 43 } 44 m<<=2;sort(q+1,q+m+1,cmp);l=0,r=n+1;rep(i,1,m) 45 { 46 while(l<q[i].l) {l++;res+=rnum[g[l]],lnum[g[l]]++;} 47 while(l>q[i].l) {res-=rnum[g[l]],lnum[g[l]]--;l--;} 48 while(r>q[i].r) {r--;res+=lnum[g[r]],rnum[g[r]]++;} 49 while(r<q[i].r) {res-=lnum[g[r]],rnum[g[r]]--;r++;} 50 ans[q[i].id]+=res*q[i].t; 51 }rep(i,1,m>>2) printf("%lld\n",ans[i]); 52 }
T3
题目大意:
有$n$条直线,求这些直线中所有两两交点中距离一定点$(x_0,y_0)$前$m$近的距离和
思路:
可以二分一个圆,判断圆内是否有$m$个交点,先求出直线和圆的交点
则若在圆上存在$ABAB$的形式则有一个交点,其中$A,B$表示直线$a,b$与圆的交点
可以使用树状数组类似数点来计算
二分出半径后,按照靠左的交点排序后,遍历圆上的点,找出$l-r$这两个交点之间的其他直线的交点
这样找出的两个直线一定是满足条件的,依次加入答案即可(为了方便使用set找着个区间
(因为标程的精度锅了,所以用$cf$的形式读入
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 100100 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD[d])%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 const db pi=acos(-1),eps=1e-6; 31 int n,m,K,c[MAXN];db tx,ty,ans,k[MAXN],b[MAXN],a[MAXN],y[MAXN]; 32 struct Data{db x,y;int id;} g[MAXN]; 33 bool operator < (Data a,Data b) {return a.x<b.x;} 34 #define fi first 35 #define se second 36 #define mp make_pair 37 void mdf(int x,int val) {for(;x<=n;x+=x&-x) c[x]+=val;} 38 int query(int x,int res=0) {for(;x;x-=x&-x) res+=c[x];return res;} 39 int cheq(int res=0) 40 { 41 int l,r;rep(i,1,m) 42 { 43 l=lower_bound(y+1,y+m+1,g[i].x)-y-1; 44 r=lower_bound(y+1,y+m+1,g[i].y)-y; 45 res+=query(r)-query(l),mdf(r,1); 46 }return res>=K; 47 } 48 db get(db k1,db k2,db b1,db b2) {return (b2-b1)/(k1-k2);} 49 int main() 50 { 51 n=read(),tx=0.001*read(),ty=0.001*read();K=read();rep(i,1,n) 52 { 53 k[i]=0.001*read(),b[i]=0.001*read(),a[i]=atan(k[i]); 54 if(tx*k[i]+b[i]>ty) a[i]+=pi/2;else a[i]-=pi/2; 55 } 56 db l=0,r=1e11,mid,d;for(;mid=(l+r)/2,l<r-eps;) 57 { 58 m=0;memset(c,0,sizeof(c));rep(i,1,n) 59 { 60 d=fabs(k[i]*tx-ty+b[i])/sqrt(k[i]*k[i]+1);if(d>mid) continue; 61 d=acos(d/mid);g[++m]=(Data){a[i]-d,a[i]+d,0}; 62 if(g[m].x<=-pi) g[m].x+=2*pi;if(g[m].y>pi) g[m].y-=2*pi; 63 if(g[m].x>g[m].y) swap(g[m].x,g[m].y);y[m]=g[m].y; 64 } 65 sort(y+1,y+m+1);sort(g+1,g+m+1);if(cheq()) r=mid;else l=mid; 66 }mid=r; 67 set <pair<db,int> > s;set <pair<db,int> > ::iterator it; 68 m=0;rep(i,1,n) 69 { 70 d=fabs(k[i]*tx-ty+b[i])/sqrt(k[i]*k[i]+1);if(d>mid) continue; 71 d=acos(d/mid);g[++m]=(Data){a[i]-d,a[i]+d,i}; 72 if(g[m].x<=-pi) g[m].x+=2*pi;if(g[m].y>pi) g[m].y-=2*pi; 73 if(g[m].x>g[m].y) swap(g[m].x,g[m].y); 74 }sort(g+1,g+m+1);int tot=0; 75 rep(i,1,m) 76 { 77 it=s.lower_bound(mp(g[i].x,0)); 78 for(;it!=s.end()&&it->fi<=g[i].y;++it,++tot) 79 { 80 if(tot==K) break;l=get(k[g[i].id],k[it->se],b[g[i].id],b[it->se]); 81 r=k[g[i].id]*l+b[g[i].id];ans+=sqrt((tx-l)*(tx-l)+(ty-r)*(ty-r)); 82 } 83 s.insert(mp(g[i].y,g[i].id));if(tot==K) break; 84 } 85 printf("%.10lf\n",ans); 86 }