温暖场,不过三道都是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=X−A,b=A−[A=B],c=B−[A̸=B],d=Y−B。
没有区间限制时答案即为
(
X
−
1
A
−
1
)
(
Y
−
1
B
−
1
)
{X-1 \choose A-1}{Y-1\choose B-1}
(A−1X−1)(B−1Y−1)(插板法)
区间限制数位
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想到了但是代码实现上很有问题。