2019雅礼集训day4 题解

温暖场,不过三道都是CF原题。
也就每次考得水一点才能排在前面了。


T1 大爷

CF1061E
题解


T2 熊猫

CF1045H

A , B , X , Y A,B,X,Y A,B,X,Y分别表示字符串中连续0的区间数,连续1的区间数,0的个数,1的个数。


a = X − A , b = A − [ A = B ] , c = B − [ A ≠ B ] , d = Y − B a=X-A,b=A-[A=B],c=B-[A\neq B],d=Y-B a=XA,b=A[A=B],c=B[A̸=B],d=YB
没有区间限制时答案即为 ( X − 1 A − 1 ) ( Y − 1 B − 1 ) {X-1 \choose A-1}{Y-1\choose B-1} (A1X1)(B1Y1)(插板法)
区间限制数位 d p dp dp讨论一下即可(略繁琐。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100,mod=1e9+7;
typedef long long ll;

int A,B,C,D,X,Y,a,b,c,d,tpy;
int n,m,ans,frc[N],nv[N];
char f[N],g[N];

inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}

inline void brt()
{
	int x,i,l=0,r=0,pr,nw;
	for(i=1;i<=m;++i) l=(l<<1)+(f[i]-'0');
	for(i=1;i<=n;++i) r=(r<<1)+(g[i]-'0');
	for(x=l;x<=r;++x){
		a=b=c=d=0;pr=(x&1);
		for(i=x>>1;i;i>>=1,pr=nw){
			nw=(i&1);
			if(nw) pr?d++:c++;
			else pr?b++:a++;
		}
		if(a==A && b==B && c==C && d==D) ad(ans,1);
	}
	printf("%d",ans);
}

inline int cal(int n,int m)
{
	if(m==n) return 1;
	if(n<0 || m<0) return 0;
	if(m>n) return 0;
	if(m==n || m==0) return 1;
	return (ll)frc[n]*nv[m]%mod*(ll)nv[n-m]%mod;
}

inline int fd(char *s,int n)
{
	if(a+b>n) return 0;
	if(a+b<n) return tpy;
	int i,re=0,ca=a,cb=b,cx=X,cy=Y;
	for(i=1;i<=n && s[i];++i);
	if(i>n) return tpy;
	for(i=1;i<=n;++i){
		if((s[i]!=s[i-1])&&(i>1)) s[i]?cx--:cy--;
		if(s[i]){
			if(s[i-1]&&(cx==cy-1 || cx==cy)&&(i>1))
				ad(re,(ll)cal(ca-1,cx-1)*cal(cb-1,cy-2)%mod);
			else if((!s[i-1])&&(cx+1==cy || cx==cy)&&(i>1))
			    ad(re,(ll)cal(ca-1,cx)*cal(cb-1,cy-1)%mod);
			cb--;
		}else ca--;
	}
	s[n]?cy--:cx--;
	if((ca==0)&&(cb==0)&&(cx==0)&&(cy==0)) ad(re,1);
	return re;
}

int main(){
	scanf("%s%s%d%d%d%d",f+1,g+1,&A,&B,&C,&D);
	n=strlen(g+1);m=strlen(f+1);
	if(n<=21) brt();
	else{
        if((B!=C)&&(B!=C-1)) {printf("0");return 0;} 
		int i;frc[0]=frc[1]=nv[0]=nv[1]=1;
		for(i=2;i<=n;++i) frc[i]=(ll)frc[i-1]*i%mod,nv[i]=(ll)(mod-mod/i)*nv[mod%i]%mod;
		for(i=2;i<=n;++i) nv[i]=(ll)nv[i-1]*nv[i]%mod;
		for(i=1;i<=m;++i) f[i]-='0';
		for(i=1;i<=n;++i) g[i]-='0';
		reverse(f+1,f+m+1);
		for(i=1;!f[i];++i);
		f[i]=0;for(--i;i;--i) f[i]=1;
		for(;(!f[m])&& m;--m);
		reverse(f+1,f+m+1);
		
		X=C,Y=C;if(B==C) Y++;
	    a=X+A;b=Y+D;
	    if(B!=((X==Y)?(X-1):X) || C!=X) {printf("0");return 0;}
		tpy=(ll)cal(a-1,X-1)*cal(b-1,Y-1)%mod;
	    
	    printf("%d",dc(fd(g,n),fd(f,m)));
	}
	return 0;
}

T3 鸽子

CF780H

f ( t ) f(t) f(t)表示 t t t时刻第一只和第二只鸽子的欧几里得距离。显然 f ( t ) f(t) f(t)是一个分段二次函数。设多边形总长为 C C C,将所有两两相邻的鸽子的距离映射到区间 ( 0 , C m ) (0,\frac Cm) (0,mC)上。

二分答案 m i d mid mid,求出所有满足 f ( t ) ≥ m i d f(t)\geq mid f(t)mid的区间,若某一处被覆盖了 m m m次,则有解,反之无解。

e p s eps eps没设好的下场:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int N=1e5+10;
const db eps=1e-9;

int n,m,num,cnt;
db len[N],sum,a,b,c,d;

inline db sqr(db x){return x*x;}

struct P{
   db x,y;
   P(db x_=0,db y_=0):x(x_),y(y_){};
   P operator +(const P&ky){return P(x+ky.x,y+ky.y);}
   P operator -(const P&ky){return P(x-ky.x,y-ky.y);}
   P operator /(const db&ky){return P(x/ky,y/ky);}
   P operator *(const db&ky){return P(x*ky,y*ky);}
   inline db sq(){return sqr(x)+sqr(y);}
}p[N],dir[N],st,ed;


inline db dis(P a,P b){return sqrt((a-b).sq());}

struct F{db ql,qr,a,b,c;}f[N<<4];

struct dat{
   db pos;int v;
   bool operator <(const dat&ky)const{
      return fabs(pos-ky.pos)<eps?v<ky.v:pos<ky.pos;
   }
}t[N<<4];

inline bool ck(db lim)
{
	int i,j;cnt=0;db l,r,z,x,y;
	for(i=1;i<=num;++i){
		a=f[i].a;b=f[i].b;c=f[i].c-lim;l=f[i].ql;r=f[i].qr;
		assert(a>-eps);
		if(fabs(a)<eps){
			if(fabs(b)<eps){if(c<eps) t[++cnt]=(dat){l,1},t[++cnt]=(dat){r,-1};}
			else{
			  z=-c/b;
			  if(b>0 && z>0) t[++cnt]=(dat){l,1},t[++cnt]=(dat){min(l+z,r),-1};
			  else if(b<0 && l+z<r) t[++cnt]=(dat){max(l+z,0.0),1},t[++cnt]=(dat){r,-1};
			}
		}else{
			z=b*b-4*a*c;if(z<0) continue;z=sqrt(z);
			x=(-b-z)/(2*a);y=(-b+z)/(2*a);
			if(l+x>r || y<0) continue;
			t[++cnt]=(dat){l+max(0.0,x),1};t[++cnt]=(dat){min(r,l+y),-1};
		}
	}
	sort(t+1,t+cnt+1);
	for(i=1,j=0;i<=cnt;++i)
	{j+=t[i].v;if(j==m) return true;}
	return false;
}

int main(){
	int i,pl=1,pr=1,id=1;P dr,dt,st,ed;
	db l=0,r,mid,res,cur=0,la,lb,avr;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i) scanf("%lf%lf",&p[i].x,&p[i].y);
	p[n+1]=p[1];
	for(i=1;i<=n;++i){
		len[i]=dis(p[i],p[i+1]);dir[i]=(p[i+1]-p[i])/len[i];
		sum+=len[i];
	}
	avr=lb=sum/m;
	for(;len[pr]<lb+eps;++pr) lb-=len[pr];
	st=p[1];ed=p[pr]+dir[pr]*lb;la=len[1];lb=len[pr]-lb;
	for(;cur+(1e-5)<sum;){
		res=min(id*avr-cur,min(la,lb));
		dt=ed-st;dr=dir[pr]-dir[pl];
		f[++num]=(F){cur-(id-1)*avr,cur-(id-1)*avr+res,dr.sq(),2*(dr.x*dt.x+dr.y*dt.y),dt.sq()};
		cur+=res;if(cur+eps>id*avr) id++;
		st=st+(dir[pl]*res);ed=ed+(dir[pr]*res);
		if(res+eps>la) {pl=pl%n+1;la=len[pl];}else la-=res;
		if(res+eps>lb) {pr=pr%n+1;lb=len[pr];}else lb-=res;
	}
	for(r=avr;r-l>eps;){
		mid=(l+r)/2.0;
		ck(mid*mid)?r=mid:l=mid;
	}
	printf("%.8lf",l);
	return 0;
}

小结

T1做过不说了。
T2还是想了有点久,思维速度有点慢了。
T3想到了但是代码实现上很有问题。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值