【题解】2020牛客寒假算法基础集训营2

比赛链接:https://ac.nowcoder.com/acm/contest/3003
其他比赛题解:
【题解】2020牛客寒假算法基础集训营1
【题解】2020牛客寒假算法基础集训营3
【题解】2020牛客寒假算法基础集训营4
【题解】2020牛客寒假算法基础集训营5


试题目录

  • A - 做游戏(签到)
  • B - 排数字(签到)
  • C - 算概率(dp)
  • D - 数三角(计算几何)
  • E - 做计数(数学)
  • F - 拿物品(思维+贪心)
  • G - 判正误(快速幂 + 模运算)


A - 做游戏(签到)

原题链接:https://ac.nowcoder.com/acm/contest/3003/A

  • 思路: 这道题要求的是获胜局数,而不是得分!!!

Code:

#include 
using namespace std;
typedef long long ll;
int main(){
    ll a,b,c;    cin>>a>>b>>c;
    ll x,y,z;    cin>>x>>y>>z;
    cout<<min(a,y)+min(b,z)+min(c,x)<<endl;
    return 0;
}


B - 排数字(签到)

原题链接:https://ac.nowcoder.com/acm/contest/3003/B

  • 思路: 1 和 6 以外不需要考虑。要让 616 子串最多一定是 61616… ,这样后面的串可以用前面的 6 ,数量为 max(min(cnt_6-1, cnt_1), 0) 。(可以理解为前面一个 6 后面 16 循环)

Code:

#include 
#include 
using namespace std;
int main(){
    int n;    cin>>n;
    string str;    cin>>str;
    int sum1=0,sum2=0;
    for(int i=0;i<str.length();i++){
        if(str[i]=='1')    sum1++;
        if(str[i]=='6')    sum2++;
    }
    cout<<max(min(sum1,sum2-1),0)<<endl;
    return 0;
}


C - 算概率(dp)

原题链接:https://ac.nowcoder.com/acm/contest/3003/C

  • 思路: 用 dp[i][j] 表示前 i 道题目做对了 j 道的概率,初始化 dp[0][0] = 1,第 j 道是否做对,有两种情况,状态转移方程为 dp[i][j] = dp[i-1][j] * (1-p[i]) + dp[i-1][j-1] * p[i] 。最后要注意的就是,概率有可能为负数,所以要加上 mod。

Code:

#include 
using namespace std;
typedef long long ll;
const int N=2e3+10;
const ll mod=1e9+7; 
ll dp[N][N],p[N];
int main(){
    int n;    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>p[i];
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=i;j++)
            dp[i][j]=(dp[i-1][j]*(1-p[i])+dp[i-1][j-1]*p[i])%mod;
    for(int i=0;i<=n;i++){
        if(dp[n][i]<0)    cout<<dp[n][i]+mod<<' ';
        else    cout<<dp[n][i]<<' ';
    }
    cout<<endl;
    return 0;
}


D - 数三角(计算几何)

原题链接:https://ac.nowcoder.com/acm/contest/3003/D

  • 思路: 先给所有坐标点排个序,然后暴力三层循环求法。一个三角形的三边长 a,b,c( c 最长 )满足 a^2 + b^2 < c^2(或存在两条边向量的点积 <0 ),则该三角形为钝角三角形。注意也要判断是否为三角形。

Code:

#include 
#include 
#include 
using namespace std;
typedef long long ll;
struct node{
    int x,y;
}arr[1000];
bool cmp(node a,node b){
    if(a.x==b.x)    return a.y<b.y;
    return a.x<b.x;
}
int main(){
    int n;    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>arr[i].x>>arr[i].y;
    sort(arr+1,arr+1+n,cmp);
    ll ans=0;
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            for(int k=j+1;k<=n;k++){
                int a = (arr[i].x-arr[j].x)*(arr[i].x-arr[j].x)+(arr[i].y-arr[j].y)*(arr[i].y-arr[j].y);
                int b = (arr[j].x-arr[k].x)*(arr[j].x-arr[k].x)+(arr[j].y-arr[k].y)*(arr[j].y-arr[k].y);
                int c = (arr[i].x-arr[k].x)*(arr[i].x-arr[k].x)+(arr[i].y-arr[k].y)*(arr[i].y-arr[k].y);
                if(c<a)    swap(c,a);
                if(c<b)    swap(c,b);
                if(sqrt(a)+sqrt(b)>sqrt(c) && a+b<c)
                    ans++;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}


E - 做计数(数学)

原题链接:https://ac.nowcoder.com/acm/contest/3003/E

  • 思路: 两边平方,得 i + j + 2 i j = k i+j+2\sqrt{ij}=k i+j+2ij =k ,显然仅当 i , j i,j i,j 都是整数且 i j ij ij 为完全平方数时才会对应一个符合条件的 k k k 。所以先打表求出 4 ∗ 1 0 7 4*10^7 4107 以内的所有完全平方数并存入数组。然后枚举 [ 1 , n ] [1,n] [1,n] 以内所有的完全平方数的因字数总和,即为不同的正整数三元组数量 ( i , j , k ) \text{}(i,j,k) (i,j,k)

Code:

#include 
#include 
using namespace std;
typedef long long ll;
const int N=4e7;
ll a[N+10];
int main(){
    int n;    cin>>n;
    int x;
    for(int i=1;;i++){
        if(i*i<=N)
            a[i]=i*i;
        else{
            x=i-1;
            break;
        }
    }
    ll ans=0;
    for(int i=1;i<=x;i++){
        if(a[i]>n)    break;
        for(int j=1;j*j<=a[i];j++){
            if(a[i]%j==0){
                if(j*j==a[i])    ans++;
                else    ans+=2;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}


F - 拿物品(思维+贪心)

原题链接:https://ac.nowcoder.com/acm/contest/3003/F

  • 思路: 要使得两人得分总和差值尽可能大,要么即要取使自己得分尽可能大的物品,也要取使对方得分尽可能少的物品,所以就要取 a+b 最大的物品。

Code:

#include 
#include 
using namespace std;
const int N=2e5;
struct node{
    int a,b,num;
}arr[N];
bool cmp(node x,node y){
    return x.a+x.b>y.a+y.b;
}
int main(){
    int n;    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>arr[i].a;
        arr[i].num=i;
    }
    for(int i=1;i<=n;i++)
        cin>>arr[i].b;
    sort(arr+1,arr+1+n,cmp);
    for(int i=1;i<=n;i++)
        if(i%2)
            cout<<arr[i].num<<' ';
    cout<<endl;
    for(int i=1;i<=n;i++)
        if(i%2==0)
            cout<<arr[i].num<<' ';
    cout<<endl;
    return 0;
}


G - 判正误(快速幂 + 模运算)

原题链接:https://ac.nowcoder.com/acm/contest/3003/G

  • 思路: 这道题就是一道快速幂模板题,唯一的难点就是会卡精度 (1e9+7) 。要注意快速幂里面不能用快速乘,快速乘一般用在 long long 数据范围,防止溢出。

Code:

#include 
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll q_pow(ll a,ll b,ll mod){
    ll ans=1,res=a;
    while(b){
        if(b&1)    ans=ans*res%mod;
        res=res*res%mod;
        b>>=1;
    }
    return ans%mod;
}

int main(){
    int t;    cin>>t;
    while(t--){
        ll a,b,c,d,e,f,g;    cin>>a>>b>>c>>d>>e>>f>>g;
        if(q_pow(a,d,mod)+q_pow(b,e,mod)+q_pow(c,f,mod)==g)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}


你可能感兴趣的:(牛客网)