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

题目来源:https://ac.nowcoder.com/acm/contest/3003#question
这场就比较菜了,差点拿了一血,但是…就差一点点 点点点 实力是六题,因为有一题数据弱了… 先写着几个水题的题解,之后再补(可能明天)
UPD:补完了~


A - 做游戏

看代码都能懂

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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()
{
    LL a,b,c,x,y,z;
    rrr(a,b,c); rrr(x,y,z);
    cout<<min(x,c)+min(y,a)+min(z,b)<<endl;
    return 0;
}


B - 排数字

统计6 和 1出现的次数 ,设分别为a b ,那么答案就是max(min(a-1,b),0)
因为最简排法是 616161616 这样子

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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;
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);
    int cnt1=0,cnt6=0;
    scanf("%s",s+1);
    FOR(i,1,n){
        if(s[i]=='1') cnt1++;
        else if(s[i]=='6') cnt6++;
    }
    cout<<max(0,min(cnt6-1,cnt1))<<endl;
    return 0;
}


C - 算概率

设dp[ i ][ j ]为前i道题做出来j道的概率,可以在复杂度O(n2)内解决
转移方程为:dp[i][j]=(dp[i-1][j]*(1-f[i])+dp[i-1][j-1]*f[i]);

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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;
LL dp[M][M];
LL 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){r(f[i]);}
    dp[0][0]=1;
    FOR(i,1,n){
        dp[i][0]=dp[i-1][0]*(1-f[i]+mod)%mod;
        FOR(j,1,i){
            dp[i][j]=(dp[i-1][j]*(1-f[i]+mod)%mod+dp[i-1][j-1]*f[i]%mod)%mod;
        }
    }
    FOR(i,0,n) cout<<dp[n][i]<<' ';
    cout<<endl;
    return 0;
}

D - 数三角

暴力,枚举三角形的三个点 a b c 通过向量乘积的正负判断是否有钝角 即可
但是要注意 三点一线的特判 if(xx*yyy==yy*xxx) return 0;

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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 point
{
    int x,y;
}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;
}
bool hhh(point a,point b,point c)
{
    int xx=b.x-a.x,yy=b.y-a.y;
    int xxx=c.x-a.x,yyy=c.y-a.y;
    if(xx*yyy==yy*xxx) return 0;
    return (xx*xxx+yy*yyy)<0;
}
int main()
{
    r(n);
    FOR(i,1,n){
        scanf("%d%d",&f[i].x,&f[i].y);
    }
    int ans=0;
    FOR(i,1,n){
        FOR(j,i+1,n){
            FOR(k,j+1,n){
                point a=f[i];
                point b=f[j];
                point c=f[k];
                if(hhh(a,b,c)||hhh(b,c,a)||hhh(c,b,a)){
                    ans++;
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}


E - 做计数

这题也算暴力吧。 首先两边平方 得到 i + j + sqrt(ij) = k
我们知道 i j k 都是整数 ,如果i
j不能开方出整数 那肯定不行
所以枚举n以内所有的平方数 1 4 9 …
然后再统计这个平方数的因子即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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);
    LL ans=0;
    FOR(i,1,n){
        int t=sqrt(i);
        if(t*t==i){
            FOR(j,1,t){
                if(i%j==0){
                    if(j==t) ans++;
                    else ans+=2;
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}


F - 拿物品

拿的物品a多或者b多对自己都是有好处的,效果相同。
我们以a+b的大小从大到小排序 正着取即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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
{
    int a,b,id;
}f[N];
bool cmp(node a,node b)
{
    return a.a+a.b>b.a+b.b;
}
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){
        r(f[i].a);
        f[i].id=i;
    }
    FOR(i,1,n) r(f[i].b);
    sort(f+1,f+n+1,cmp);
    for(int i=1;i<=n;i+=2) cout<<f[i].id<<' ';
    cout<<endl;
    for(int i=2;i<=n;i+=2) cout<<f[i].id<<' ';
    cout<<endl;
    return 0;
}


G - 判正误

这题数据太水,就是 hash ,看后面数据怎么加强 我的代码是错的
你们可以多取几个模 增加正确率

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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
{
    int a,b,id;
}f[N];
bool cmp(node a,node b)
{
    return a.a+a.b>b.a+b.b;
}
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;
}
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()
{
    int t;r(t);
    while(t--){
        LL a,b,c,d,e,f,g;
        rrr(a,c,e); rrr(b,d,f); r(g);
        if(qpow(a,b)+qpow(c,d)+qpow(e,f)==g) cout<<"Yes\n";
        else cout<<"No\n";
    }
    return 0;
}

H - 施魔法

居然真是DP,dp[ i ]表示的是 取前i个所消耗的最少魔力
转移方程为:dp[i]=min(dp[i-1]+f[i]-f[i-1],dp[i-m]+f[i]-f[i-m+1]);
可以这样想,假如现在已经分了k段了,你要么把下一个加入第k段,要么让这最后k个另成一段,取最小值.

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
using namespace std;
const int N=1e6+5;
const int M=2e3+5;
const int sz=17;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
typedef pair<int,int> pt;
LL n,m;
int f[N];
int 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); r(m);
    FOR(i,1,n) r(f[i]);
    sort(f+1,f+n+1);
    FOR(i,1,n) dp[i]=f[i]-f[1];
    FOR(i,2*m,n){
        dp[i]=min(dp[i-1]+f[i]-f[i-1],dp[i-m]+f[i]-f[i-m+1]);
    }
    cout<<dp[n]<<endl;
    return 0;
}


I - 建通道

我的写法复杂了,因为一开始题目看错了 写成这丑样了,然后懒得改太多…
如果有相同的元素 那肯定让他们之间连通 因为花费为0 把相同的去重掉就好了。 然后我们肯定是希望lowbit越小越好,我们就从最低为开始往高位枚举,设目前到了第k+1位 那如果这个元素&(1<<k) =1 把他放入一个集合A =0 放入一个集合 B 如果这两个集合都不为空 ,我们让这两个集合的元素互相连通就是让所以元素连通了。 比如 A中有 a1 a2 ,B中有b1 b2 ,我们让a1 连 b1 b2 ,a2连b1即可,一共花费即为 (1<<k)*(n-1)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
#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;
int f[N];
LL ans;
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 hhh(vector<int> v,LL st)
{
    vector<int> v1,v2;
    bool f1=0,f2=0;
    FOR(i,0,v.size()-1){
        if(v[i]&st){
            f1=1;
            v1.push_back(v[i]);
        }
        else{
            f2=1;
            v2.push_back(v[i]);
        }
    }
    if(f1&&f2){
        LL res=st*(v1.size()+v2.size()-1);
        ans=min(ans,res);
        return ;
    }
    if(f1) hhh(v1,st<<1);
    if(f2) hhh(v2,st<<1);
}
int main()
{
    r(n);
    FOR(i,1,n){
        r(f[i]);
    }
    sort(f+1,f+n+1);
    n=unique(f+1,f+n+1)-f-1;
    ans=0;
    if(n==0||n==1) cout<<ans<<endl;
    else{
        ans=INF;
        vector<int> v;
        FOR(i,1,n) v.push_back(f[i]);
        hhh(v,1);
        cout<<ans<<endl;
    }
    return 0;
}


J - 求函数

这题看出来了是线段树 但是自己不知道改维护什么
在这里插入图片描述
那就维护k的乘积和那个和就完事~

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
using namespace std;
const int N=1e6+5;
const int M=2e3+5;
const int sz=17;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
typedef pair<LL,LL> pt;
LL n,m;
int kkk[N],ans1[N],ans2[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;
}
void update(int k,int l,int r,int pos,int kk,int b)
{
    if(l==r){
        ans1[k]=kk;
        ans2[k]=b;
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=pos) update(ls,pos,kk,b);
    else update(rs,pos,kk,b);
    ans1[k]=1ll*ans1[k<<1]*ans1[k<<1|1]%mod;
    ans2[k]=(1ll*ans2[k<<1]*ans1[k<<1|1]+ans2[k<<1|1])%mod;
}
pt merge_pt(pt p1,pt p2)
{
    return mp(1ll*p1.first*p2.first%mod,(1ll*p1.second*p2.first%mod+p2.second)%mod);
}
pt query(int k,int l,int r,int x,int y)
{
    if(x<=l&&r<=y){
        return mp(ans1[k],ans2[k]);
    }
    int mid=(l+r)>>1;
    pt pp=mp(1,0);
    if(mid>=x) pp=merge_pt(pp,query(ls,x,y));
    if(mid<y) pp=merge_pt(pp,query(rs,x,y));
    return pp;
}
int main()
{
    r(n); r(m);
    FOR(i,1,n) r(kkk[i]);
    FOR(i,1,n){
        LL b;r(b);
        update(1,1,n,i,kkk[i],b);
    }
    while(m--){
        int op;
        r(op);
        if(op==1){
            int i,k,b;
            rrr(i,k,b);
            update(1,1,n,i,k,b);
        }
        else{
            int l,r;
            r(l); r(r);
            pt pp=query(1,1,n,l,r);
            //cout<<pp.first<<' '<<pp.second<<endl;
            cout<<(pp.first+pp.second)%mod<<endl;
        }
    }
    return 0;
}


下次加油哇~争取多A个题

发布了71 篇原创文章 · 获赞 89 · 访问量 8529

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/104199801