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 }
View Code

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
",ans[i]);
46 }
View Code

有结论之后的B题是bzoj 5016这道题的弱化版

题意为:给定了两个区间$[l1,r1]$和$[l2,r2]$,求$sumlimits_{i=0}^{infty} get(l1,r1,i) imes 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
",ans[i]);
52 }
View Code

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
",ans);
86 }
View Code
原文地址:https://www.cnblogs.com/yyc-jack-0920/p/10640476.html