2020牛客寒假算法基础集训营1 【A - J】

题目来源:https://ac.nowcoder.com/acm/contest/3002
实力只有八题,觉得发挥的比较好了。(也许今晚会补题 也许明天,保证不咕~)。
upd: 更新完毕 ~ 请放心食用~


A - honoka和格点三角形

假如一边平行x轴,那分两种情况 此边长为2,此边长为1
平行y轴同理,最后发现这两种情况之和多算了 一边平行x轴另一边平行y轴的情况
减去就完事了(多出来的就是 1x2的矩形数量的4倍)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    r(n); r(m);
    LL ans=0;
    //平行x轴 长为2
    ans=(ans+2ll*(m-2)%mod*m%mod)%mod; //边上的两个
    if(n>2) ans=(ans+2ll*(n-2)%mod*(m-2)%mod*m%mod)%mod;
    //长为1
    ans=(ans+1ll*min(4ll,2ll*(n-2))*(m-1)%mod*m%mod)%mod;
    if(n>4) ans=(ans+2ll*(n-4)%mod*(m-1)%mod*m%mod)%mod;
    //cout<
    swap(n,m);
    ans=(ans+2ll*(m-2)%mod*m%mod)%mod; //边上的两个
    if(n>2) ans=(ans+2ll*(n-2)%mod*(m-2)%mod*m%mod)%mod;
    //长为1
    ans=(ans+1ll*min(4ll,2ll*(n-2))*(m-1)%mod*m%mod)%mod;
    if(n>4) ans=(ans+2ll*(n-4)%mod*(m-1)%mod*m%mod)%mod;
    //cout<
    LL num=((n-1)*(m-2)%mod+(m-1)*(n-2)%mod)%mod;
    ans=(ans-num*4ll%mod+mod)%mod;
    cout<<ans<<endl;
    return 0;
}


B - kotori和bangdream

这题题目坑了我,居然只有两种情况 我以为有n+1种情况…不难

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    int a,b,x;
    rrr(n,x,a); r(b);
    double xx=x*1.0/100;
    double ans=n*a*xx+n*b*(1-xx);
    printf("%.2f\n",ans);
    return 0;
}


C - umi和弓道

还是分两种情况讨论,方法类似 就只说板子在x轴上吧
如果x0*x[ i ]>0说明 板子不可能挡住这个点,忽略就行,其他的点都有可能通过x轴上的板子阻挡箭。设点(x0,y0)与(x[ i ],y[ i ])连起来和x轴交于点p,那如果p在板子上就可以挡住此点了。 我们只需要挡住n-k个点,尺取就ok了。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
double x[N],y[N];
double f[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    double x0,y0;
    scanf("%lf%lf",&x0,&y0);
    r(n); r(m);
    FOR(i,1,n){
        scanf("%lf%lf",&x[i],&y[i]);
    }
    m=n-m;
    double ans1=2e10;
    int cnt=0;
    FOR(i,1,n){
        if(y[i]*y0<0){
            f[++cnt]=x0-y0*(x0-x[i])/(y0-y[i]);
        }
    }
    sort(f+1,f+cnt+1);
    //FOR(i,1,cnt){
    //    cout<
    //}
    //cout<
    FOR(i,1,cnt-m+1){
        ans1=min(f[i+m-1]-f[i],ans1);
    }
    //x板子
    double ans2=2e10;
    cnt=0;
    FOR(i,1,n){
        if(x[i]*x0<0){
            f[++cnt]=y0-x0*(y0-y[i])/(x0-x[i]);
        }
    }
    sort(f+1,f+cnt+1);
    //FOR(i,1,cnt){
    //    cout<
    //}
    //cout<
    FOR(i,1,cnt-m+1){
        ans1=min(f[i+m-1]-f[i],ans1);
    }
    //cout<
    if(ans1==2e10&&ans2==2e10) cout<<-1<<endl;
    else printf("%.8f\n",min(ans1,ans2));
    //y板子
    return 0;
}


D - hanayo和米饭

这题很水啊,想象成一个桶,哪个桶没有就是哪个…

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    r(n);
    FOR(i,1,n-1){
        int a;
        r(a);
        f[a]++;
    }
    FOR(i,1,n){
        if(f[i]==0){
            cout<<i<<endl;
            break;
        }
    }
    return 0;
}


E - rin和快速迭代

找n的因子个数只需要sqrt(n)次判断 就算是最大的n=1e12 开方之后是1e6
再开方 1e3 哪怕 还需要开1e3次方 也不会超时。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int hhh(LL x)
{
    int ans=0;
    FOR(i,1,sqrt(x)){
        if(x%i==0){
            if(i==sqrt(x)) ans++;
            else ans+=2;
        }
    }
    return ans;
}
int main()
{
    r(n);
    LL now=n;
    int ans=0;
    while(1){
        now=hhh(now);
        if(now==2){
            cout<<ans+1<<endl;
            break;
        }
        //cout<
        ans++;
    }
    return 0;
}


F - maki和tree

我觉得这题很有意思,我的做法是带权并查集 开始的并查集就是所有白点相连即属于一个集合,然后**加一个数量权**表示这个集合有多少个点。对于每个黑点,假如它连着x个白点集合 这个不难算吧
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct edge
{
    int to,next;
}e[N];
int head[N<<1];
bool color[N];
char str[N];
int dad[N];
int num[N];
int gg[N];
int cnt;
vector<int> v;
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
void add_edge(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt;
}
int seek(int k)
{
    return dad[k]==k?k:dad[k]=seek(dad[k]);
}
int main()
{
    r(n);
    scanf("%s",str+1);
    FOR(i,1,n){
        dad[i]=i;
        num[i]=1;
        if(str[i]=='B'){
            color[i]=1;
            v.push_back(i);
        }
        else color[i]=0;
    }
    cnt=0;
    FOR(i,1,n-1){
        int a,b;
        r(a); r(b);
        add_edge(a,b);
        add_edge(b,a);
        if(color[a]==0&&color[b]==0){
            int x=seek(a),y=seek(b);
            if(x!=y){
                dad[x]=y;
                num[y]+=num[x];
            }
        }
    }
    LL ans=0;
    for(int i=0;i<v.size();i++){
        int now=v[i];
        int cc=0;
        LL sum=0;
        for(int i=head[now];i;i=e[i].next){
            int get=e[i].to;
            if(color[get]==0){
                int tmp=seek(get);
                gg[++cc]=num[tmp];
                sum+=num[tmp];
            }
        }
        ans+=sum;
        FOR(i,1,cc){
            ans+=1ll*gg[i]*(sum-gg[i]);
            sum-=gg[i];
        }
    }
    cout<<ans<<endl;
    return 0;
}


G - eli和字符串

前缀和+二分 代码应该好懂

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N][26];
char s[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    r(n); r(m);
    scanf("%s",s+1);
    FOR(i,1,n){
        FOR(j,0,25){
            if(s[i]-'a'==j) f[i][j]=f[i-1][j]+1;
            else f[i][j]=f[i-1][j];
        }
    }
    int ans=INF;
    FOR(i,1,n){
        int l=i,r=n;
        int res=INF;
        while(l<=r){
            int mid=(l+r)>>1;
            bool flag=1;
            FOR(j,0,25){
                if(f[mid][j]-f[i-1][j]>=m){
                    flag=0;
                    break;
                }
            }
            if(!flag){
                res=mid;
                r=mid-1;
            }
            else l=mid+1;
        }
        if(res!=INF) ans=min(res-i+1,ans);
    }
    if(ans==INF) cout<<-1<<endl;
    else cout<<ans<<endl;
    return 0;
}

H - nozomi和字符串

和上一题一样…感觉水了 ,前缀和+二分

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
int f[N][2];
char s[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    r(n); r(m);
    scanf("%s",s+1);
    FOR(i,1,n){
        if(s[i]=='1'){
            f[i][1]=f[i-1][1]+1;
            f[i][0]=f[i-1][0];
        }
        else{
            f[i][0]=f[i-1][0]+1;
            f[i][1]=f[i-1][1];
        }
    }
    int ans1=0;
    FOR(i,1,n){
        int l=i,r=n;
        int res=INF;
        if(n-i+1<=ans1) break;
        while(l<=r){
            int mid=(l+r)>>1;
            if(f[mid][1]-f[i-1][1]<=m){
                l=mid+1;
                res=mid;
            }
            else r=mid-1;
        }
        //cout<
        if(res!=INF) ans1=max(res-i+1,ans1);
    }
    int ans2=0;
    FOR(i,1,n){
        int l=i,r=n;
        int res=INF;
        if(n-i+1<=ans2) break;
        while(l<=r){
            int mid=(l+r)>>1;
            if(f[mid][0]-f[i-1][0]<=m){
                l=mid+1;
                res=mid;
            }
            else r=mid-1;
        }
        if(res!=INF) ans2=max(res-i+1,ans2);
    }
    cout<<max(ans1,ans2)<<endl;
    return 0;
}


I - nico和niconiconi

此题是补题。参考链接:https://www.cnblogs.com/SwiftAC/p/12260779.html
我当时有想过dp,但是就是不知道怎么转移 tcl tcl !
类似的字符串切割方法也可以学一下,挺方便的string s(str+i-3,str+i+1);

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=3e5+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
char str[N];
LL dp[N];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    r(n); LL a,b,c;
    rrr(a,b,c);
    scanf("%s",str+1);
    FOR(i,1,n){
        if(i>=4){
            string s(str+i-3,str+i+1);
            if(s=="nico"){
                dp[i]=max(dp[i-4]+a,dp[i]);
            }
            else dp[i]=max(dp[i],dp[i-1]);
        }
        if(i>=6){
            string s(str+i-5,str+i+1);
            if(s=="niconi"){
                dp[i]=max(dp[i-5]+b,dp[i]);
            }
            else dp[i]=max(dp[i],dp[i-1]);
        }
        if(i>=10){
            string s(str+i-9,str+i+1);
            if(s=="niconiconi"){
                dp[i]=max(dp[i-10]+c,dp[i]);
            }
            else dp[i]=max(dp[i],dp[i-1]);
        }
    }
    cout<<dp[n]<<endl;
    return 0;
}


J - u’s的影响力

这题是个数学题,我不是数学手,搞了一天才搞懂
用到了 矩阵快速幂+欧拉降幂+快速幂
前两项特判就不说了
从第三项开始 都会呈现一定的规律
f( 3) =x1 * y1 * ab
f( 4) =x1 * y2 * a2b
f( 5) =x2 * y3 * a4
f( 6) =x3 * y5 * a7

设 xx yy aa 分别为x y a 的幂
再设g(1)=1 g(2)=1 ,当i>3时 g(i)=g(i-1)+g(i-2)
那么xx=g(n-2) ,yy=g(n-1) aa=g(n)-1 【n>3】
所以我们来一次矩阵快速幂就好了~
构造矩阵:

1 1
0 0

但是斐波拉契数列到几十项就快爆了,我们一定要取模,但是怎么取了?
这里用到了欧拉降幂 假如我们要求ab ,现在我们用mod=1e9+7,题目也说了mod是个质数,当a=mod时,可能出现a=k*mod的情况,我们要提前特判此时 ab%mod=0 即可(我被这里卡了几个小时)
最后是个快速幂,我就不说了.

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct node
{
    LL f[3][3];
}t;
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
node mult(const node &a,const node &b)
{
    node res;
    FOR(i,1,2)
    FOR(j,1,2){
        res.f[i][j]=0;
        FOR(k,1,2) res.f[i][j]=(res.f[i][j]+a.f[i][k]*b.f[k][j])%(mod-1);
    }
    return res;
}
LL qpow(LL a,LL p)
{
    LL res=1;
    while(p){
        if(p&1) res=res*a%mod;
        a=a*a%mod;
        p>>=1;
    }
    return res;
}
int main()
{
    LL x,y,a,b;
    rrr(n,x,y); r(a); r(b);
    x%=mod; y%=mod; a%=mod; b%=(mod-1);
    if(n==1){cout<<x<<endl; return 0;}
    else if(n==2){cout<<y<<endl; return 0;}
    if(x==0||y==0||a==0){cout<<0<<endl; return 0;}
    LL xx,yy,aa;
    node now;
    now.f[1][1]=now.f[2][2]=1; now.f[1][2]=now.f[2][1]=0;//单位矩阵
    t.f[1][1]=t.f[1][2]=t.f[2][1]=1; t.f[2][2]=0;  //构造出来的矩阵
    n-=2;
    while(n){
        if(n&1) now=mult(now,t);
        t=mult(t,t);
        n>>=1;
    }
    aa=now.f[1][1]+now.f[1][2];
    yy=now.f[2][1]+now.f[2][2];
    yy=yy%(mod-1);
    xx=(aa-yy+(mod-1))%(mod-1);
    aa=(aa-1+(mod-1))%(mod-1);
    //cout<
    LL ans=qpow(x,xx)*qpow(y,yy)%mod*qpow(qpow(a,aa)%mod,b)%mod;
    cout<<ans<<endl;
    return 0;
}

你可能感兴趣的:(Contests)