D.Deep800080
题目大意:给定n个点的坐标,和一条线段两端的坐标,在线段上找到一个点作为圆心,画半径为r的圆,求圆最多能覆盖多少个点。
分析:考虑一个点刚好被圆覆盖,线段上对应的圆心的位置。一般会有两个(存在圆心满足).
圆心在l---r位置,点x一定会被覆盖。那么我们就可以将点变成线段上的一段区间。这段区间上的点就是能覆盖到点x.
那么将所有点进行转换成一段区间进行差分计算,就能得到最优原点的位置。
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<ctype.h> //#include<bits/stdc++.h> using namespace std; typedef double db; const db eps=1e-8; const db PI=acos(-1.0); const int maxn=3e5+10; int n; inline db readb() { int f=1;db x=0;char s=getchar(); for( ;!isdigit(s);s=='-' && (f=-1),s=getchar()); for( ;isdigit(s);x=x*10+s-48,s=getchar()); if( s=='.' ) for( db l=0.1,s=getchar();isdigit(s);x=x+(s-48)*l,l/=10,s=getchar() ); return x*f; } int sgn( double d ) { return (d>eps)-(d<-eps); }; // 精度判断 struct point{ db x,y; point(){ x=y=0; } point(db _x,db _y ){ x=_x,y=_y; } point operator + ( const point &rhs ) const { return point(x+rhs.x,y+rhs.y); } point operator - ( const point &rhs ) const { return point(x-rhs.x,y-rhs.y); } point operator / ( const int &rhs ) const { return point(x/rhs,y/rhs); } db operator * ( const point &rhs ) const { return 1ll*x*rhs.y-1ll*y*rhs.x; } point operator * ( const db &rhs ) const { return point(x*rhs,y*rhs);} db dot( const point &rhs ) const { return 1ll*x*rhs.x+1ll*y*rhs.y; } void get(){ x=readb(),y=readb(); } bool operator == ( const point &rhs ) const { return x==rhs.x && y==rhs.y; } bool operator < ( const point &rhs ) const { return sgn(x-rhs.x)<0 || sgn(x-rhs.x)==0 && sgn(y-rhs.y)<0 ; } point Rotate( db rad ) { return point(x*cos(rad)-y*sin(rad), x*sin(rad)+y*cos(rad) ); } db sdis() { return sqrt(x*x+y*y); } // bool operator < ( const point &rhs ) const { return (*this)*rhs>0 ; } 极角排序 }; db dist( point a,point b ) { return sqrt( (b-a).dot(b-a) ); } bool getdir( point p[],int n ) // true 逆时针存边 { db ans=0; for( int i=0;i<n;i++ ) ans+=p[i]*p[(i+1)%n]; return sgn(ans)>0; } struct segment{ // 线段 point s,e; segment(){} segment( point _s,point _e ) { s=_s,e=_e; } void get( point _s,point _e ) { s=_s,e=_e; } bool inter( const segment &l1, const segment &l2 ) // 两线段是否交 1 交 / 0 不交 { return max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) && max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) && max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) && max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) && sgn( (l2.s-l1.e)*(l1.s-l1.e) )*sgn( (l2.e-l1.e)*(l1.s-l1.e) ) <= 0 && sgn( (l1.s-l2.e)*(l2.s-l2.e) )*sgn( (l1.e-l2.e)*(l2.s-l2.e) ) <= 0; } bool inter1( const segment &l1,const segment &l2 ) // 两线段是否正规相交 1 交 / 0 不交 { if( inter(l1,l2) ) { if( l1.s==l2.s && l1.e==l2.e || l1.s==l2.e && l1.e==l2.s ) return true; //重合 else if( l1.s==l2.s || l1.s==l2.e || l1.e==l2.s || l1.e==l2.e ) return false; // 端点相交 return true; } return false; } bool OnSeg( const point &p ) //判断点在线段上 1 在/ 0 不在 { return sgn( (s-p)*(e-p) )==0 && sgn( (p.x-s.x)*(p.x-e.x) )<=0 && sgn( (p.y-s.y)*(p.y-e.y) )<=0; } pair<point,int> operator & ( const segment &rhs ) const{ // 两直线相交问题 point res=s; //交点 if( sgn( (s-e)*(rhs.s-rhs.e) )==0 ) { if( sgn( (rhs.s-s)*(rhs.e-s) )==0 ) return make_pair(res,0); // 两直线重合 else return make_pair( res,1 ); // 两直线平行 } db t= ( (s-rhs.s)*(rhs.s-rhs.e) )/ ( (s-e)*(rhs.s-rhs.e) ) ; //单位化 res.x+=(e.x-s.x)*t; res.y+=(e.y-s.y)*t; return make_pair(res,2); // 有交点 } point NearestPointToLineSeg( const point &P,const segment &L ) // 线段 最近点对 { point result; db t = ( (P-L.s).dot(L.e-L.s) )/( (L.e-L.s).dot(L.e-L.s) ); if( t >= 0 && t <= 1 ) { result.x = L.s.x + (L.e.x - L.s.x)*t; result.y = L.s.y + (L.e.y - L.s.y)*t; } else { if(dist(P,L.s) < dist(P,L.e)) result = L.s; else result = L.e; } return result; } }; //--------------------直线---------------- struct sLine{ // 直线 point s,e; sLine(){} sLine( point _s,point _e ) { s=_s,e=_e; } sLine operator * ( const db &rhs ) const { return sLine(s*rhs,e*rhs); } pair<point,int> operator & ( const sLine &rhs ) const{ // 两直线相交问题 point res=s; //交点 if( sgn( (s-e)*(rhs.s-rhs.e) )==0 ) { if( sgn( (rhs.s-s)*(rhs.e-s) )==0 ) return make_pair(res,0); // 两直线重合 else return make_pair( res,1 ); // 两直线平行 } db t= ( (s-rhs.s)*(rhs.s-rhs.e) )/ ( (s-e)*(rhs.s-rhs.e) ) ; //单位化 res.x+=(e.x-s.x)*t; res.y+=(e.y-s.y)*t; return make_pair(res,2); // 有交点 } int segLineCross( const sLine &s1,const segment &s2 ) // 直线和线段相交 { point a=s1.s,b=s1.e,c=s2.s,d=s2.e; int d1,d2; d1 = sgn( (b-a)*(c-a) ); d2 = sgn( (b-a)*(d-a) ); if( (d1^d2)==-2 ) return 1; // 标准相交 if( d1==0 || d2==0 ) return 2; // 不标准相交 return 0; // 不相交 } db getDistance( point A ) //点到直线的距离 { return fabs((A-s)*(A-e)/dist(s,e) ); } sLine Circle_inter( point o,sLine X ,db R ) //圆与直线交点 { point o2 = o; o2.x += X.s.y - X.e.y; o2.y += X.e.x - X.s.x; o2= o2 = (sLine(o,o2)&X).first; db t = sqrt(R * R - (o2 - o).sdis() * (o2 - o).sdis()) / (X.s - X.e).sdis(); point p1 = o2 - (X.e - X.s) * t; point p2 = o2 + (X.e - X.s) * t; return sLine(p1,p2); } }; point p[maxn]; sLine s; struct node{ db x,y; int c; }cc; int main() { int n,r,a,b; n=readb(),r=readb(),a=readb(),b=readb(); for( int i=0;i<n;i++ ) p[i].get(); s=sLine(point(0,0),point(a,b)); vector<node> g; for( int i=0;i<n;i++ ) { if( s.getDistance(p[i])<=r ) { sLine tmp=s.Circle_inter(p[i],s,r); node p1={tmp.s.x,tmp.s.y,1}; node p2={tmp.e.x,tmp.e.y,-1}; if( p1.x>p2.x || ( sgn(p1.x-p2.x)==0 && p1.y>p2.y )) swap(p1.c,p2.c); g.push_back(p1); g.push_back(p2); } } sort(g.begin(),g.end(),[&]( node x,node y ) { if( sgn(x.x-y.x)==0 && sgn(x.y-y.y)==0 ) return x.c>y.c; if( sgn(x.x-y.x)==0 ) return x.y<y.y; return x.x<y.x; } ); int ans=0,sum=0; for( int i=0;i<g.size();i++ ) { sum+=g[i].c; ans=max(ans,sum); } printf("%d\n",ans); }
E.Zeldain Garden
大致题意:求区间[n,m]的每个数的因子和。
分析:我们可以求出每个数作为因子出现的次数。
.
那么这个式子就是整除分块。
# include <bits/stdc++.h> using namespace std; typedef long long LL; LL X(LL n) { LL l, r; LL ans = 0; for( l = 1; l <= n; l = r+1) { r = n/(n/l); ans += n/l * (r - l + 1); } return ans; } int main(){ LL n,m; cin>> n>>m; printf("%lld\n",X(m)-X(n-1)); }
H.Ponk Warshall
大致题意:给定两个由A,G,C,T组成的字符串,我们可以操作第一个串,任意位置进行交换,求变成第二个串的最小操作次数。
分析:对于交换,我们肯定优先考虑长度小的循环节,先从长度为2 的循环节进行操作,然后再从长度为3的循环节进行操作,最后操作长度为4的循环节。(这样可以用最小的操作次数满足尽可能多的位置字符相同)
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll poww(ll a,ll b,ll mod){ ll ans = 0;//a乘b等价转化为b个a相加,和快速幂原理一致 while(b){ if(b&1) ans = (ans+a)%mod; a = (a+a)%mod; b>>=1; } return ans; } int a[100][100]; int b[4]={'A','G','C','T'}; int main() { string s1; string s2; cin>>s1>>s2; int n=s1.size(); int tot=0; for(int i=0;i<n;i++){ if( s2[i]==s1[i] ) continue; if(a[s2[i]][s1[i]]){ a[s2[i]][s1[i]]--; tot++; }else{ a[s1[i]][s2[i]]++; } } int c; do{ c=min(a[b[0]][b[1]],min(a[b[1]][b[2]],a[b[2]][b[0]])); tot+=c*2; a[b[0]][b[1]]-=c; a[b[1]][b[2]]-=c; a[b[2]][b[0]]-=c; }while(next_permutation(b,b+4)); do{ c=min(a[b[0]][b[1]],min(a[b[1]][b[2]],a[b[2]][b[3]])); c=min(c,a[b[3]][b[0]]); tot+=c*3; a[b[0]][b[1]]-=c; a[b[1]][b[2]]-=c; a[b[2]][b[3]]-=c; a[b[3]][b[0]]-=c; }while(next_permutation(b,b+4)); printf("%d\n",tot); }