codeforce1046 Bubble Cup 11 - Finals 题解
比赛的时候开G开了3h结果rose说一句那唯一一个AC的是羊的心态就崩了。。
这套题感觉质量挺好然后就back了下
A: AI robots
有三个限制条件;相互能够看见和智商的差。使用主席树,可以维护两个状态,分别是其中一个“看见”和“智商”,这样的做法就无法利用K<=20的条件了。
利用扫描线+线段树,可以解决相互看见的约束(大概是我做过最神的扫描线了)对于一个点,处理出它能够看见的最前和最后点,和它的位置一起当做一条线,最前点加入这个点的位置,最后点删除这个点的影响,点的位置的线相当于一个询问,所以处理的顺序就是加入、询问、去除。解决了这点,显而易见的做法就是对于每个智商建一棵线段树暴力修改。每次插入一条链(与主席树类似的做法)可以防止空间溢出
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; struct robot{int pos,r,iq;}rb[110000]; int poslen,pos[110000],iqlen,iq[110000]; struct line { int op,l,r,pos,iq; line(){} line(int OP,int L,int R,int POS,int IQ){op=OP,l=L,r=R,pos=POS,iq=IQ;} }li[310000];int lilen; bool cmp(line l1,line l2){return l1.pos==l2.pos?l1.op<l2.op:l1.pos<l2.pos;} struct trnode { int lc,rc;LL c; }tr[6100000];int trlen,rt[110000]; int change(int now,int L,int R,int p,LL c) { if(now==0) { now=++trlen; tr[now].lc=tr[now].rc=tr[now].c=0; } if(L==R)tr[now].c+=c; else { int mid=(L+R)/2; if(p<=mid)tr[now].lc=change(tr[now].lc,L,mid,p,c); else tr[now].rc=change(tr[now].rc,mid+1,R,p,c); tr[now].c=tr[tr[now].lc].c+tr[tr[now].rc].c; } return now; } LL getsum(int now,int L,int R,int l,int r) { if(now==0||(L==l&&R==r))return tr[now].c; int mid=(L+R)/2; int lc=tr[now].lc,rc=tr[now].rc; if(r<=mid) return getsum(lc,L,mid,l,r); else if(mid+1<=l)return getsum(rc,mid+1,R,l,r); else return getsum(lc,L,mid,l,mid)+getsum(rc,mid+1,R,mid+1,r); } int main() { // freopen("1.in","r",stdin); // freopen("1.out","w",stdout); int n,K; scanf("%d%d",&n,&K); poslen=0,iqlen=0; for(int i=1;i<=n;i++) { scanf("%d%d%d",&rb[i].pos,&rb[i].r,&rb[i].iq); pos[++poslen]=rb[i].pos; iq[++iqlen]=rb[i].iq; } sort(pos+1,pos+poslen+1); poslen=unique(pos+1,pos+poslen+1)-pos-1; sort(iq+1,iq+iqlen+1); iqlen=unique(iq+1,iq+iqlen+1)-iq-1; //----------------------LSH------------------------------- lilen=0; for(int i=1;i<=n;i++) { int p=lower_bound(pos+1,pos+poslen+1,rb[i].pos)-pos; int L=lower_bound(pos+1,pos+poslen+1,rb[i].pos-rb[i].r)-pos; int R=upper_bound(pos+1,pos+poslen+1,rb[i].pos+rb[i].r)-pos-1; li[++lilen]=line(0,p,0,L,rb[i].iq); li[++lilen]=line(1,L,R,p,rb[i].iq); li[++lilen]=line(2,p,0,R,rb[i].iq); } sort(li+1,li+lilen+1,cmp); //-------------------------preprare------------------------------ LL ans=0; trlen=0;memset(rt,0,sizeof(rt)); for(int i=1;i<=lilen;i++) { if(li[i].op==0) { int q=lower_bound(iq+1,iq+iqlen+1,li[i].iq)-iq; rt[q]=change(rt[q],1,n,li[i].l,1); } else if(li[i].op==2) { int q=lower_bound(iq+1,iq+iqlen+1,li[i].iq)-iq; rt[q]=change(rt[q],1,n,li[i].l,-1); } else { int L=lower_bound(iq+1,iq+iqlen+1,li[i].iq-K)-iq; int R=upper_bound(iq+1,iq+iqlen+1,li[i].iq+K)-iq-1; for(int j=L;j<=R;j++) ans+=getsum(rt[j],1,n,li[i].l,li[i].r); ans--; } } printf("%I64d\n",ans/2); return 0; }
B: Hyperspace Highways
我比较菜并不会圆方树,所以就去学了学(所以我就不在这里讲了)
这个东西怎么和我之前做freda的传呼机用的方法那么像啊
题目给了个很有意思的性质,就是在一个点双里面的点距离为1,那么直接广义圆方树,答案就是树上距离/2
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; struct node { int x,y,next; }e[1100000];int elen,elast[110000]; void eins(int x,int y) { elen++; e[elen].x=x;e[elen].y=y; e[elen].next=elast[x];elast[x]=elen; } int z,dfn[110000],low[110000]; int top,sta[110000]; int cnt; vector<int>vec[110000]; void V_DCC(int x) { dfn[x]=low[x]=++z; sta[++top]=x; for(int k=elast[x];k;k=e[k].next) { int y=e[k].y; if(dfn[y]==0) { V_DCC(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { int k;cnt++; do { k=sta[top];top--; vec[cnt].push_back(k); }while(k!=y); vec[cnt].push_back(x); } } else low[x]=min(low[x],dfn[y]); } } //--------------------------get_V-DCC--------------------------- node a[3100000];int len,last[210000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int id; void composition(int n)//��һ�ù���Բ���� { id=n; len=0;memset(last,0,sizeof(last)); for(int i=1;i<=cnt;i++) { id++; for(int j=0;j<vec[i].size();j++) ins(id,vec[i][j]),ins(vec[i][j],id); } } int Bin[30],dep[210000],f[30][210000]; void dfs(int x) { for(int i=1;Bin[i]<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=f[0][x]) { f[0][y]=x; dep[y]=dep[x]+1; dfs(y); } } } int getdis(int x,int y) { if(dep[x]<dep[y])swap(x,y); int ret=0; for(int i=22;i>=0;i--) if(dep[x]-dep[y]>=Bin[i])ret+=Bin[i],x=f[i][x]; if(x==y)return ret; for(int i=22;i>=0;i--) if(dep[x]>=Bin[i]&&f[i][x]!=f[i][y]) ret+=Bin[i]*2, x=f[i][x], y=f[i][y]; return ret+2; } int main() { int n,m,Q,x,y; scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); eins(x,y),eins(y,x); } z=top=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); V_DCC(1); composition(n); Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2; f[0][1]=0;dep[1]=0;dfs(1); while(Q--) { scanf("%d%d",&x,&y); printf("%d\n",getdis(x,y)/2); } return 0; }
C: Space Formula
水水的贪心决策包容性,首先自己肯定选最大的,然后大到小枚举,一个大的如果连最小的和它匹配都无法比当前小,就直接不管,因为有单调性所以这样肯定最优
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int a[210000],p[210000]; int main() { int n,id,K; scanf("%d%d",&n,&id); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)scanf("%d",&p[i]); K=p[1]+a[id]; int ans=1; for(int i=1,j=n;i<=n;i++,j--) { if(i==id)continue; if(a[i]+p[j]>K) { ans++; j++; } } printf("%d\n",ans); return 0; }
D: Interstellar battle
好题。让我对概率与期望的理解又加深了。
设剩下V个点,E条边,那么会剩下V-E个联通分量
总的期望=E(V-E) (联通分量个数)=E(V) (点的个数) - E(E) (边的条数)= sigema p(v)-sigema p(u)p(v)
两个东西分开算一下
第一个很好搞。第二个其实就是所有的边,因为修改是会把一个点所有的边都改了的,那我们让根节点管理所有儿子到它的边,那么修改一个点就只会影响当前点和他的父亲,O(1)修改,完了。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[210000];int len,last[110000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int fa[110000]; double p[110000],f[110000]; void dfs(int x) { f[x]=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]) { fa[y]=x; dfs(y); f[x]+=p[y]; } } } int main() { int n; scanf("%d",&n); p[0]=0; for(int i=1;i<=n;i++) scanf("%lf",&p[i]), p[i]=1.0-p[i]; len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y);x++,y++; ins(x,y),ins(y,x); } fa[1]=0;dfs(1); double V=0,E=0; for(int i=1;i<=n;i++) V+=p[i], E+=p[i]*f[i]; int Q; scanf("%d",&Q); while(Q--) { int x;double pp; scanf("%d%lf",&x,&pp); x++, pp=1-pp; V-=p[x]; E-=p[x]*f[x]; E-=p[fa[x]]*f[fa[x]]; f[fa[x]]=f[fa[x]]-p[x]; p[x]=pp; f[fa[x]]=f[fa[x]]+p[x]; V+=p[x]; E+=p[x]*f[x]; E+=p[fa[x]]*f[fa[x]]; printf("%.5lf\n",V-E); } return 0; }
E: Ancient civilizations
真的太感动了,做了一天的题终于过了!
首先先做一次凸包,假如是01交错一定无解
两种情况,一种是凸包上都是一种点,一种是0,1各1段
第一种,在凸包里面找一个不同的点,把凸包拆分成多个三角形
第二种,自己YY一下,画下图,相邻相同颜色的点去找不同颜色的点,可以发现固定选择一个边边的点然后拆分就可以保证不重不漏的把凸包画出来了
这样做有什么用呢?现在我们搞出来的三角形两个点同色,一个点不同色
假如这个三角形里面没有那个不同色的点,就可以直接连边了
否则还可以拆成三个三角形,不停递归下去就可以解决了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; struct point{int x,y,op,id;}p[1100]; int multi(point p1,point p2,point p0) { int x1,y1,x2,y2; x1=p1.x-p0.x; y1=p1.y-p0.y; x2=p2.x-p0.x; y2=p2.y-p0.y; return x1*y2-x2*y1; } bool cmp(point p1,point p2){return multi(p1,p2,p[1])>0;} int aslen,asx[1100],asy[1100]; void pb(int x,int y){asx[++aslen]=x;asy[aslen]=y;} int n; int top,sta[1100],insta[1100]; bool in_triangle(point p1,point p2,point p3,point p0) { int t1=multi(p1,p0,p2); int t2=multi(p2,p0,p3); int t3=multi(p3,p0,p1); if((t1<0&&t2<0&&t3<0)||(t1>0&&t2>0&&t3>0))return true; return false; } void separate(point p1,point p2,point p3,int L,int R)//p1,p2同色 { if(L>R)return ; int k=-1; for(int i=L;i<=R;i++) if(p[i].op!=p1.op) { k=R; if(insta[R]!=0) { insta[i]=insta[R]; sta[insta[i]]=i; insta[R]=0; } swap(p[R],p[i]); break; } pb(p3.id,p[k].id); //----------------找到分割点------------------------- int l=L,r=L-1; bool bk=false; for(int i=l;i<=R;i++) if(i!=k) { if(in_triangle(p1,p2,p[k],p[i])) { if(p[i].op!=p1.op)bk=true; r++; if(insta[r]!=0) { insta[i]=insta[r]; sta[insta[i]]=i; insta[r]=0; } swap(p[r],p[i]); } } if(bk==false) { for(int i=l;i<=r;i++) pb(p1.id,p[i].id); } else separate(p1,p2,p[k],l,r); //-------------------------------------------------- l=r+1;bk=false; for(int i=l;i<=R;i++) if(i!=k) { if(in_triangle(p1,p3,p[k],p[i])) { if(p[i].op!=p3.op)bk=true; r++; if(insta[r]!=0) { insta[i]=insta[r]; sta[insta[i]]=i; insta[r]=0; } swap(p[r],p[i]); } } if(bk==false) { for(int i=l;i<=r;i++) pb(p3.id,p[i].id); } else separate(p3,p[k],p1,l,r); //-------------------------------------------------- l=r+1;bk=false; for(int i=l;i<=R;i++) if(i!=k) { if(in_triangle(p2,p3,p[k],p[i])) { if(p[i].op!=p3.op)bk=true; r++; if(insta[r]!=0) { insta[i]=insta[r]; sta[insta[i]]=i; insta[r]=0; } swap(p[r],p[i]); } } if(bk==false) { for(int i=l;i<=r;i++) pb(p3.id,p[i].id); } else separate(p3,p[k],p2,l,r); } void graham() { top=0;sta[++top]=1,sta[++top]=2; memset(insta,0,sizeof(insta));insta[1]=1,insta[2]=2; for(int i=3;i<=n;i++) { while(top>1&&multi(p[sta[top]],p[i],p[sta[top-1]])<=0) { insta[sta[top]]=0; top--; } sta[++top]=i;insta[sta[top]]=top; } //------------------------------------------------------ int s=0; for(int i=2;i<=top;i++) s+=(p[sta[i-1]].op^p[sta[i]].op); s+=(p[sta[1]].op^p[sta[top]].op); if(s>2)printf("Impossible\n"); else if(s==0) { int cc=p[sta[1]].op,k=-1; for(int i=1;i<=n;i++) if(insta[i]==0&&p[i].op!=cc) { k=n; if(insta[n]!=0) { insta[i]=insta[n]; sta[insta[i]]=i; insta[n]=0; } swap(p[n],p[i]); break; } int L=1,R=0; for(int i=2;i<=top;i++) { pb(p[sta[i-1]].id,p[sta[i]].id); bool bk=false; for(int j=L;j<=n;j++) if(insta[j]==0&&j!=k) { if(k==-1||in_triangle(p[sta[i-1]],p[sta[i]],p[k],p[j])) { if(p[j].op!=cc)bk=true; R++; if(insta[R]!=0) { insta[j]=insta[R]; sta[insta[j]]=j; insta[R]=0; } swap(p[R],p[j]); } } if(bk==false) { for(int j=L;j<=R;j++) pb(p[sta[i]].id,p[j].id); } else separate(p[sta[i-1]],p[sta[i]],p[k],L,R); L=R+1; } bool bk=false; for(int j=L;j<=n;j++) if(insta[j]==0&&j!=k) { if(k==-1||in_triangle(p[sta[top]],p[sta[1]],p[k],p[j])) { if(p[j].op!=cc)bk=true; R++; if(insta[R]!=0) { insta[j]=insta[R]; sta[insta[j]]=j; insta[R]=0; } swap(p[R],p[j]); } } if(bk==false) { for(int j=L;j<=R;j++) pb(p[sta[top]].id,p[j].id); } else separate(p[sta[top]],p[sta[1]],p[k],L,R); } else //------------------------------------------------------------------ { int be;bool bk=false; for(int i=1;i<=top;i++) if(p[sta[i]].op==0) { if(bk==false) be=i, bk=true; } else bk=false; int L=1,R=0; int i,k=(be-1+top-1)%top+1; for(i=be%top+1;p[sta[i]].op==0;i=i%top+1) { int u=(i-1+top-1)%top+1; pb(p[sta[u]].id,p[sta[i]].id); bool bk=false; for(int j=L;j<=n;j++) { if(insta[j]==false&&in_triangle(p[sta[u]],p[sta[i]],p[sta[k]],p[j])) { if(p[j].op!=0)bk=true; R++; if(insta[R]!=0) { insta[j]=insta[R]; sta[insta[j]]=j; insta[R]=0; } swap(p[R],p[j]); } } if(bk==false) { for(int j=L;j<=R;j++) pb(p[sta[i]].id,p[j].id); } else separate(p[sta[u]],p[sta[i]],p[sta[k]],L,R); L=R+1; } //---------------------------分别处理0和1--------------------------- ------- k=(i-1+top-1)%top+1; for(i=i%top+1;i!=be;i=i%top+1) { int u=(i-1+top-1)%top+1; pb(p[sta[u]].id,p[sta[i]].id); bool bk=false; for(int j=L;j<=n;j++) { if(insta[j]==false&&in_triangle(p[sta[u]],p[sta[i]],p[sta[k]],p[j])) { if(p[j].op!=1)bk=true; R++; if(insta[R]!=0) { insta[j]=insta[R]; sta[insta[j]]=j; insta[R]=0; } swap(p[R],p[j]); } } if(bk==false) { for(int j=L;j<=R;j++) pb(p[sta[i]].id,p[j].id); } else separate(p[sta[u]],p[sta[i]],p[sta[k]],L,R); L=R+1; } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].op),p[i].id=i-1; if(p[i].y<p[1].y||(p[i].y==p[1].y&&p[i].x<p[1].x)) swap(p[i],p[1]); } if(n==1){printf("0\n");return 0;} else if(n==2) { if(p[1].op==p[2].op)printf("1\n0 1\n"); else printf("0\n"); return 0; } sort(p+2,p+n+1,cmp); aslen=0;graham(); if(aslen!=0) { printf("%d\n",aslen); for(int i=1;i<=aslen;i++) printf("%d %d\n",asx[i],asy[i]); } return 0; }
F: Splitting money
全场最水题,模拟特判一下就完了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL a[210000]; int main() { int n;LL x,f; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%I64d",&a[i]); scanf("%I64d%I64d",&x,&f); LL ans=0; for(int i=1;i<=n;i++) { ans+=a[i]/(x+f); a[i]%=(x+f); if(a[i]>x)ans++; } printf("%I64d\n",ans*f); return 0; }
G: Space Isaac
转化模型太巧妙了!
对于一个数,表示它的方式是[0,x]区间头尾选和[x+1~m]区间头尾选。
无法表示当且仅当a数组里面的数都是两两匹配的
有一个想法就是建一个数组,让b[a[i]]=1,然后做马拉车
然而数的范围1e9不资瓷
但是这里只有0,1哦,把0的一段看做一个点,1看做一个点,0的段的长度就是两个相邻1的差
所以就差分之后做马拉车就好
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int a[210000],len,b[410000],p[410000]; int as[210000],aslen; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); len=0,b[++len]=-2; for(int i=1;i<n;i++) b[++len]=a[i+1]-a[i], b[++len]=-1; b[len]=-3; int k=0;p[k]=0; for(int i=1;i<=len;i++) { int Lk=k-p[k]+1,Rk=k+p[k]-1; int j=k-(i-k); if(Lk<=j)p[i]=min(p[j],j-Lk+1); else p[i]=0; while(b[i+p[i]]==b[i-p[i]]&&i-p[i]>0&&i+p[i]<=len)p[i]++; if(i+p[i]-1>Rk)k=i; } for(int i=1;i<n;i++) { if( (i==1||p[i]>=i-1) && (i==n-1||p[i+n]>=n-i-1) ) { int d1=a[1]+a[i],d2=a[i+1]+a[n]-m; if(d1==d2)as[++aslen]=d1; } } if(p[n]>=n-1)as[++aslen]=(a[1]+a[n])%m; sort(as+1,as+aslen+1); printf("%d\n",aslen); for(int i=1;i<aslen;i++)printf("%d ",as[i]); if(aslen!=0)printf("%d\n",as[aslen]); return 0; }
H: Palindrome Pairs
三水题的最后一道,明显状压然后暴力修改
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<map> using namespace std; typedef long long LL; map<int,LL>mp; char ss[1100000]; bool v[30]; int main() { int n;LL ans=0; scanf("%d",&n); for(int i=1;i<=n;i++) { memset(v,0,sizeof(v)); scanf("%s",ss+1);int len=strlen(ss+1); for(int i=1;i<=len;i++) { int x=ss[i]-'a'; v[x]^=1; } int d=0; for(int i=0;i<=25;i++) if(v[i]==1)d|=(1<<i); ans+=mp[d]; for(int i=0;i<=25;i++) ans+=mp[d^(1<<i)]; mp[d]++; } printf("%I64d\n",ans); return 0; }
I: Say Hello
dis去掉根号以后,和t构成了一个二次函数,解这个二次函数分类讨论即可
(有点码农但是和E比起来不算什么)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; double qg[5][5],qc[5]; void guess() { for(int j=1;j<=3;j++) { for(int i=j;i<=3;i++) { if(abs(qg[i][j])>1e-8) { for(int k=1;k<=3;k++)swap(qg[i][k],qg[j][k]); swap(qc[i],qc[j]); break; } } for(int i=1;i<=3;i++) { if(i==j)continue; double rate=qg[i][j]/qg[j][j]; for(int k=j;k<=3;k++)qg[i][k]-=qg[j][k]*rate; qc[i]-=qc[j]*rate; } } } int n,ans,now;bool bk;double d1,d2; void change(double d,int w) { if(w==0) { if(d>d2)now=2,bk=true; else if(d>d1)now=1; } else { if(d<=d1) { if(bk==true)ans++,bk=false; now=0; } else if(d<=d2)now=1; } } double ax1,ay1,ax0,ay0,ax2,ay2; double bx1,by1,bx0,by0,bx2,by2; double getdis(double x1,double y1,double x2,double y2) { return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); } void calc() { double dis1=getdis(ax1,ay1,bx1,by1); double dis0=getdis(ax0,ay0,bx0,by0); double dis2=getdis(ax2,ay2,bx2,by2); qg[1][1]=0.0*0.0,qg[1][2]=0.0,qg[1][3]=1.0,qc[1]=dis1; qg[2][1]=0.5*0.5,qg[2][2]=0.5,qg[2][3]=1.0,qc[2]=dis0; qg[3][1]=1.0*1.0,qg[3][2]=1.0,qg[3][3]=1.0,qc[3]=dis2; guess(); double a=qc[1]/qg[1][1],b=qc[2]/qg[2][2],c=qc[3]/qg[3][3]; if(fabs(a)<=1e-8&&fabs(b)<=1e-8)return ; if(fabs(a)<=1e-8) { if(b>0)change(dis2,0); else change(dis2,1); } else { if(0<=-b/(2.0*a)&&-b/(2*a)<=1) { double mdis=((4.0*a*c)-b*b)/(4.0*a); if(mdis>=0) { if(a>0)change(mdis,1),change(dis2,0); else change(mdis,0),change(dis2,1); } else { if(a>0)change(0,1),change(mdis,0),change(0,1),change(dis2,0); } } else if(-b/(2*a)<0) { if(a>0)change(dis2,0); else change(dis2,1); } else { if(a>0)change(dis2,1); else change(dis2,0); } } } int main() { scanf("%d%lf%lf",&n,&d1,&d2);d1*=d1,d2*=d2; scanf("%lf%lf",&ax1,&ay1); scanf("%lf%lf",&bx1,&by1); int dis=getdis(ax1,ay1,bx1,by1); ans=0; if(dis<=d1)ans++,now=0,bk=false; else if(dis<=d2)now=1,bk=true; else now=2,bk=true; for(int i=2;i<=n;i++) { scanf("%lf%lf",&ax2,&ay2); scanf("%lf%lf",&bx2,&by2); ax0=(ax1+ax2)/2,ay0=(ay1+ay2)/2; bx0=(bx1+bx2)/2,by0=(by1+by2)/2; calc(); ax1=ax2,ay1=ay2; bx1=bx2,by1=by2; } printf("%d\n",ans); return 0; }
J: Self-exploration
观察一波性质可以发现c01=c10时1的块数比0的多1,而且0的块数为c01
若c01=c10-1块数相同为c10,其他情况不合法
再加上c00和c11,可以把0的个数和1的个数都算出来
然后类似数位DP的做法,前后界相减
数位DP时,对于当前位是0,那么直接取没办法搞别的
1的话,这一位取0后面就可以随便取,而取的方案数是可以组合数搞出来的。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=1e9+7; char sa[110000],sb[110000]; void jian() { int len=strlen(sa+1),tp; for(int i=len;i>=1;i--) if(sa[i]=='1'){tp=i;break;} sa[tp]='0'; for(int i=tp+1;i<=len;i++)sa[i]='1'; if(tp==1) { for(int i=1;i<len;i++)sa[i]=sa[i+1]; sa[len]='\0'; } } void exgcd(LL a,LL b,LL &x,LL &y) { if(a==0) { x=0,y=1; return ; } else { LL tx,ty; exgcd(b%a,a,tx,ty); x=ty-b/a*tx; y=tx; } } LL getinv(LL A) { LL B=mod,x,y; exgcd(A,B,x,y); return (x%B+B)%B; } LL fac[110000],fac_inv[110000]; void init() { fac[0]=1; fac_inv[0]=1; for(int i=1;i<=100000;i++) fac[i]=(fac[i-1]*i)%mod, fac_inv[i]=getinv(fac[i]); } LL getC(int n,int m)//n+1������ֳ�m+1�� { if(n<m)return 0; if(n==-1&&m==-1)return 1; if(n==0&&m==-1)return 0; return fac[n]*fac_inv[m]%mod*fac_inv[n-m]%mod; } int len,a[110000]; int sumz,sumo,bckz,bcko; int calc() { if(a[1]==0)return 0; if(len==1)return 1; int now_sumz=0,now_sumo=1,now_bckz=0,now_bcko=1,last=1; LL ans=0; for(int i=2;i<=len;i++) { if(a[i]==0) { if(last==0)now_sumz++; else last=0,now_bckz++,now_sumz++; } else { int rem_sumz=sumz-now_sumz-1,rem_sumo=sumo-now_sumo,rem_bckz=bckz-now_bckz-(last==1),rem_bcko=bcko-now_bcko; ans= (ans + getC(rem_sumz-1,rem_bckz+1-1)*getC(rem_sumo-1,rem_bcko-1)%mod + getC(rem_sumz-1,rem_bckz-1)*getC(rem_sumo-1,rem_bcko-1)%mod )%mod; if(last==1)now_sumo++; else last=1,now_bcko++,now_sumo++; } if(now_sumz>sumz||now_bckz>bckz||now_sumo>sumo||now_bcko>bcko)break; } if(now_sumz==sumz&&now_bckz==bckz&&now_sumo==sumo&&now_bcko==bcko)ans++; return ans; } int main() { // freopen("1.in","r",stdin); // freopen("1.out","w",stdout); init(); scanf("%s",sa+1);jian(); scanf("%s",sb+1); int c00,c01,c10,c11;int tp=0; scanf("%d%d%d%d",&c00,&c01,&c10,&c11); if(c10-c01>1||c10-c01<0){printf("0\n");return 0;} bckz=c10,sumz=c00+bckz; bcko=c10+(c01==c10),sumo=c11+bcko; len=strlen(sa+1); if(len<sumz+sumo)a[1]=0; else if(len>sumz+sumo){len=sumz+sumo;for(int i=1;i<=len;i++)a[i]=1;} else {for(int i=1;i<=len;i++)a[i]=sa[i]-'0';} LL d0=calc(); len=strlen(sb+1); if(len<sumz+sumo)a[1]=0; else if(len>sumz+sumo){len=sumz+sumo;for(int i=1;i<=len;i++)a[i]=1;} else {for(int i=1;i<=len;i++)a[i]=sb[i]-'0';} LL d1=calc(); printf("%lld\n",((d1-d0)%mod+mod)%mod); return 0; }