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);
}