2020牛客寒假算法基础集训营1 J题可以回顾回顾

老子叫甜甜 提交于 2020-02-07 15:01:58

2020牛客寒假算法基础集训营1

这套题整体来说还是很简单的。

 

A.honoka和格点三角形

这个题目不是很难,不过要考虑周全,面积是1,那么底边的长度可以是1也可以是2,

注意底边1和2会有重复的,所以要注意去除这个重复部分的。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
const int mod=1e9+7;
int main(){
    ll n,m,ans=0;
    scanf("%lld%lld",&n,&m);
    ans=2*(m-2)%mod*m%mod*(n-1)%mod;
    ans+=2*(n-2)%mod*n%mod*(m-1)%mod;
    ans+=2*(m-1)%mod*(m-2)%mod*(n-2)%mod;
    ans+=2*(n-1)%mod*(n-2)%mod*(m-2)%mod;
    ans%=mod;
    printf("%lld\n",ans);
    return 0;
}
A

 

B.kotori和bangdream

这个题目也很简单,因为每一个音符的概率都是确定的。。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
 
int main(){
    int n,x,a,b;
    cin>>n>>x>>a>>b;
    double ans=n*x*a+n*(100-x)*b;
    ans/=100.0;
    printf("%.2f\n",ans);
    return 0;
}
B

 

C.umi和弓道

这个可能看起来稍微复杂一点,不过整体还是很简单,

把所有可以投影到y轴的投影到y轴,可以投影到x轴的投影到x轴。

然后排个序,求长度最短的n-k个点。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
typedef long long ll;
long double dx[maxn],dy[maxn];
long double x[maxn],y[maxn];
int judge(ll x,ll y){
    if(x>0&&y>0) return 1;
    if(x<0&&y>0) return 2;
    if(x<0&&y<0) return 3;
    if(x>0&&y<0) return 4;
}
int main(){
    ll n,k;
    long double x0,y0;
    scanf("%Lf%Lf%lld%lld",&x0,&y0,&n,&k);
    int f=judge(x0,y0);
    int num=0,numx=0,numy=0;
    for(int i=1;i<=n;i++){
        scanf("%Lf%Lf",&x[i],&y[i]);
        int ans=judge(x[i],y[i]);
        if(ans==f) num++;
        else if(x0*x[i]>0) numx++;
        else if(y0*y[i]>0) numy++;
    }
    if(num+numx>k&&num+numy>k){
        printf("-1\n");
        return 0;
    }
    int cntx=0,cnty=0;
    for(int i=1;i<=n;i++){
        if(x[i]*x0<0){
//            cout<<"i="<<i<<" x[i]="<<x[i]<<" y[i]="<<y[i]<<endl;
            dy[++cnty]=(y0-y[i])/(x0-x[i])*(-x0)+y0;
//            printf("dy[%d]=%Lf\n",cnty,dy[cnty]);
        }
        if(y0*y[i]<0){
            dx[++cntx]=(x0-x[i])/(y0-y[i])*(-y0)+x0;
        }
    }
    int res=n-k;
    sort(dy+1,dy+1+cnty);
    sort(dx+1,dx+1+cntx);
    long double ans=2e9;
    for(int i=res;i<=cntx;i++){
//        printf("dx[%d]=%Lf\n",i,dx[i]);
        ans=min(ans,dx[i]-dx[i-res+1]);
    }
    for(int i=res;i<=cnty;i++){
//        printf("dy[%d]=%Lf dy[%d]=%Lf\n",i,dy[i],i-res+1,dy[i-res+1]);
        ans=min(ans,dy[i]-dy[i-res+1]);
    }
    printf("%.6Lf\n",ans);
    return 0;
}
C

 

D.hanayo和米饭

这个太签到了

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
 
int vis[maxn];
 
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int x;
        scanf("%d",&x);
        vis[x]=1;
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            printf("%d\n",i);
            return 0;
        }
    }
}
D

 

E.rin和快速迭代

 这个题目f函数其实求的就是约数的个数,这个还是很好求的,

把这个数唯一分解,x=p1^a1*p2^a2*....*pn^an

那么这个数的约数的个数就是 num=(a1+1)*(a2+1)*...*(an+1)

这个就暴力求就可以了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
typedef long long ll;
const int mod=1e9+7;
ll v[maxn],isp[maxn],m;
void init1()
{
    for(int i=2;i<maxn;i++){
        if(v[i]==0){
            isp[m++]=i;
            v[i]=i;
        }
        for(int j=0;j<m;j++){
            if(v[i]<isp[j]||i*isp[j]>maxn) break;
            v[i*isp[j]]=isp[j];
        }
    }
}
ll judge(ll x){
    ll ans=1,p=1;
    for(int i=0;i<m;i++){
        while(x%isp[i]==0){
//            printf("isp[%d]=%d\n",i,isp[i]);
            p++,x/=isp[i];
        }
        ans*=p,p=1;
        if(x==1) break;
    } 
    if(x>1) ans*=2;
//    printf("x=%lld ans=%lld\n",x,ans);
    return ans;
}

int main(){
    init1();
    ll n,res=0;
    scanf("%lld",&n);
    while(n>2) n=judge(n),res++;
    printf("%lld\n",res);
    return 0;
}
E

 

F.maki和tree

这个题目我觉得我写的挺复杂的,

我是先预处理出白色块的连通块。

然后对于每一个黑块去枚举它周围的白色连通块。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
struct node{
    int v,nxt;
    node(int v=0,int nxt=0):v(v),nxt(nxt){}
}e[maxn*2];
int head[maxn],cnt;
void add(int u,int v){
    e[++cnt]=node(v,head[u]);
    head[u]=cnt;
    e[++cnt]=node(u,head[v]);
    head[v]=cnt;
}
int f[maxn],sum[maxn];
char s[maxn];
void dfs(int u,int pre){
    f[u]=pre,sum[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==pre) continue;
        dfs(v,u);
        if(s[u]!='B'&&s[v]!='B') sum[u]+=sum[v];
    }
}
void dfs1(int u,int pre){
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==pre) continue;
        if(s[u]!='B'&&s[v]!='B') sum[v]=max(sum[v],sum[u]);
        dfs1(v,u);
    }
}
ll ans=0;
void dfsans(int u,int pre){
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==pre) continue;
        dfsans(v,u);
    }
    if(s[u]!='B') return ;
    ll all=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(s[v]=='B') continue;
        all+=sum[v];
        ans-=sum[v]*(sum[v]-1)/2;
    }
    ans+=all*(all-1)/2;
}
int main(){
    int n;
    scanf("%d%s",&n,s+1);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    dfs(1,-1),dfs1(1,-1);
    dfsans(1,-1);
    printf("%lld\n",ans);
}
F

 

G.eli和字符串

这个题目很简单,直接暴力枚举26个字母即可。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
char s[maxn];
int num[30],pos[30][maxn];
int main(){
    int n,k;
    scanf("%d%d%s",&n,&k,s+1);
    int slen=strlen(s+1);
    for(int i=1;i<=slen;i++){
        int x=s[i]-'a';
        num[x]++;
        pos[x][num[x]]=i;
    }
    int ans=inf;
    for(int i=0;i<26;i++){
        if(num[i]<k) continue;
        int cnt=0;
        for(int j=k;j<=num[i];j++) ans=min(ans,pos[i][j]-pos[i][j-k+1]+1);
    }
    if(ans>=inf) ans=-1;
    printf("%d\n",ans);
    return 0;
}
G

 

H.nozomi和字符串

这个是一个二分,二分最大长度即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
const int mod=1e9+7;
char s[maxn];
int n,k,slen;
int num[2][maxn];
bool check(int x){
    for(int i=x;i<=slen;i++){
        int len0=num[0][i]-num[0][i-x];
        int len1=num[1][i]-num[1][i-x];
        if(len0<=k||len1<=k) return true;
    }
    return false;
}
int main(){
    scanf("%d%d%s",&n,&k,s+1);
    slen=strlen(s+1);
    for(int i=1;i<=slen;i++){
        num[0][i]=num[0][i-1];
        num[1][i]=num[1][i-1];
        num[s[i]-'0'][i]++;
    }
    int l=0,r=n,ans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}
H

 

I.nico和niconiconi

这个是一个dp,注意细节的处理。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
typedef long long ll;
char cur[]={'n','i','c','o'},s[maxn];
ll dp[maxn];
int main(){
    ll n,a,b,c;
    scanf("%lld%lld%lld%lld%s",&n,&a,&b,&c,s+1);
    for(int i=1;i<=n;i++){
        dp[i]=max(dp[i-1]+a,dp[i]);
        if(i>=2) dp[i]=max(dp[i],dp[i-2]+b);
        if(i>=3) dp[i]=max(dp[i],dp[i-3]+c);
    }
    ll ans=0;
    int num=0,pos=0,slen=strlen(s+1);
    s[++slen]='~';
    for(int i=1;i<=slen;i++){
        if(s[i]==cur[pos]) {
            pos++;
            if(pos==4) num++,pos=0;
        }
        else{
            ll res=dp[num];
            if(pos>=2){
                if(num>=1) res=max(dp[num-1]+b,res);
                if(num>=2) res=max(dp[num-2]+c,res);
            }
            ans+=res,num=0,pos=0;
            if(s[i]==cur[pos]) pos++;
        }
    }
    printf("%lld\n",ans);
    return 0;
}
/*
19 1 2 5
niconiconiniconico
*/
I

 

J.u's的影响力

这个推一下就会发现,x和y的指数都是斐波那契数列的一项,a^b的指数是斐波那契数列的前缀和。

所以都可以用矩阵快速幂解决,斐波那契数列前缀和也可以用矩阵快速幂解决。

推荐资料:大斐波拉契数列及斐波拉契前缀和(m阶前缀和)求解

斐波那契数列总(这个挺好的)

但是这个还有几个点需要注意,第一个:斐波那契数列求的是指数,所以不可以直接对mod取模,而是要对mod-1取模,因为费马小定理。

ap-1 mod p == 1 所以只可以对p-1取模。

第二个就是a是p的倍数时,不满足费马小定理,这个要分开考虑。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const long long mod = 1e9+7;

int UP;
struct mat
{
    long long mn[10][10];
    mat() {
        for(int i = 0;i<UP;i++) {
            for(int j = 0;j<UP;j++) {
                mn[i][j]=0;
            }
        }
        for(int i = 0;i<UP;i++) {
            mn[i][i] = 1;
        }
    }
    void init(){
        for(int i=0;i<UP;i++){
            for(int j=0;j<UP;j++){
                mn[i][j]=0;
            }
        }
    }
   mat operator * (const mat& a) {
        mat res;
        for(int i = 0;i<UP;i++) {
            res.mn[i][i] = 0;
        }
        for(int i=0;i<UP;i++) {
            for(int j=0;j<UP;j++) {
                for(int k=0;k<UP;k++) {
                    res.mn[i][j] += mn[i][k]*a.mn[k][j]%(mod-1);
                    res.mn[i][j] %= (mod-1);
                }
            }
        }
        return res;
    }
};

mat fast(mat a,long long c) {
    mat res = mat();
    while(c) {
        if(c&1) res  = res * a;
        a = a*a;
        c >>= 1;
    }
    return res;
}
ll quick_mul(ll a,ll b,ll mod)
{
    ll ans = 0;
    while(b)
    {
        if (b & 1) ans = (ans + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return ans;
}

ll quick_pow(ll a,ll b,ll mod)
{
    ll ans = 1;
    while(b)
    {
        if (b & 1) ans = quick_mul(ans, a, mod);
        a = quick_mul(a, a, mod);
        b >>= 1;
    }
    return ans;
}
int main(){
    UP=2;
    ll n,x,y,a,b;
    scanf("%lld%lld%lld%lld%lld",&n,&x,&y,&a,&b);
    if(n==1) {
        printf("%lld\n",x%mod);
        return 0;
    }
    if(n==2){
        printf("%lld\n",y%mod);
        return 0;
    }
    if(x%mod==0||y%mod==0||a%mod==0){
        printf("0\n");
        return 0;
    }
    mat res;res.init();
    res.mn[1][1]=0,res.mn[0][0]=res.mn[0][1]=res.mn[1][0]=1;
    res=fast(res,n-2);
    x=quick_pow(x,res.mn[1][0],mod);
    y=quick_pow(y,res.mn[0][0],mod);
    a%=mod,a=quick_pow(a,b,mod);
    UP=3,res.init();
    res.mn[0][1]=res.mn[1][0]=res.mn[1][1]=1;
    res.mn[2][0]=res.mn[2][1]=res.mn[2][2]=1;
    res=fast(res,n-3);
    a=quick_pow(a,res.mn[2][1]+res.mn[2][2],mod);
    printf("%lld\n",quick_mul(quick_mul(a,x,mod),y,mod));
    return 0;
}
J

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!