牛客周赛61

目录

A.Letter Song ~ 致十年后的我们

B.简单图形问题 - 0123

C.小红的机器人构造 - Ⅰ+Ⅱ+Ⅲ

D.小红的差值构造 - easy+hard+extreme


A.Letter Song ~ 致十年后的我们

https://ac.nowcoder.com/acm/contest/91072/A

1.思路  (AC ^ ^)

                将字符串的年份转化为整型+10后再转化为字符串输出

2.函数

(1)截取指定长度的字符串,前开后闭        

string s = "2024-9-22";
string re = s.substr(0,4);    // "2024"

(2)将字符串转化为整数

string s = "2024";          // std::意思是特定命名空间,stoi(string to integer)
int year = std::stoi(s);    // 2024

(3)将整数转化为字符串

int year = 2024;
string re = std::to_string(year);    // "2024"

B.简单图形问题 - 0123

https://ac.nowcoder.com/acm/contest/91072/B

1.思路  (AC ^ ^)

        根据面积直接算边长,判断是否为整数(等边三角形面积        S=\frac{\sqrt{3}}{4}a^2        )

2.函数

(1)判断一个数是否为整数,小数+整数和整数部分的差值是否小于某个阈值

bool whe(x){
    const double ep = 1e-9;            // 1e-9 = 1*10^-9
    return fabs(x - floor(x)) < ep;    // fabs计算浮点数的绝对值,floor计算<=x最大整数
}

3.其他

        只有两种可能,要么是0,要么是3,因为题目给出的面积s为整数,所以不可能是等边三角形,只要判断所给出的面积能否构成正方形即可

C.小红的机器人构造 - Ⅰ+Ⅱ+Ⅲ

https://ac.nowcoder.com/acm/contest/91072/C

1.思路

        Ⅰ x轴、y轴两个方向独立,只要到达(x,y)对应的方向上的步数足够即可,如x=3,y=2,U>=3&&R>=2即可,注意这里的x=3,y=2对应坐标轴是(2,3)

        Ⅱ 因为已经确定可以到达相应的位置,直接输出正好到达该位置的步数即可,如x=3,y=2,输出UUURR(举个例子,并非一定是这样),其他舍去

        Ⅲ 需要利用组合数的相关知识进行求解,先求解y方向上的所有可能

        利用for循环枚举所有的可能,假设D删除i步,U删除j步, 则所有可能情况为:C(U,j)*C(D,i)

        假设x>0,需满足:(U-j)-(D-i)= x        即:j = U - D + i -x        即:U-j = D + x - i             

        假设x>0,需满足:(D-i)-(U-j)= -x        即:j = U - D +i -x        即:U-j = D + x - i

    for(int i=0;i<=n;i++){
        ansx+=C(ctu,ctd+x-i)*C(ctd,i)%mod;
        ansy+=C(ctr,ctl+y-i)*C(ctl,i)%mod;
    }

        发现结果相同,因此不必分开讨论x的情况来计算,因为组合数中C(U,j)与C(U,U-j)等价的,所以最终结果就是:C(U,D+x-i)*C(D,i)

        这里为什么是D删除i步,而不是U呢,其实都可以,看自己的喜好,再假设U删i步,D删j步

        假设x>0,需满足:(U-i)- (D-j)= x        即:j = x + i + D - U        即:D-j = U - x - i    

        假设x<0,需满足:(D-j)-(U-i)= -x        即:j = x + i + D - U        即:D-j = U - x - i

    for(int i=0;i<=n;i++){
        ansx+=C(ctu,i)*C(ctd,ctu-x-i)%mod;
        ansy+=C(ctr,i)*C(ctl,ctr-y-i)%mod;
    }

x方向的结果以及结论类似,求解后把两个情况相乘(求解过程注意保证%mod,避免结果溢出)

2.函数

(1)快速幂函数,即求a^b(a的b次方)

int qpow(int a, int b){
    int t = 1;
    int y = a;
    while(b){
        if(b&1){
            t = (t*y)%mod;
        }
        y = (y*y)%mod;
        b>>=1;    // 向右移一位,相当于b/=2
    }
    return t;
}

(2)利用逆元求解组合数

const int mod = 1e9+7,N = 1e6+10;
int a[N],b[N];    // a[i]表示i的阶层,b[i]表示i的逆元

void init(){
    int n = 1e6;
    a[0]=1;
    b[0]=1;
    for(int i=1;i<=n;i++){
        a[i] = a[i-1]*i%mod;
    }                               // 利用费马小定理求解n!的逆元x
    b[n] = qpow(a[n],mod-2);        // n!*x 三 1 (mod p)    n!^p-1 三 1 (mod p)
    for(int i=n-1;i>=1;i--){        // n!*x 三 n!^n-1    x 三 n!^p-2
        b[i] = b[i+1]*(i+1)%mod;    // n!的逆元为n!^(mod-2)    (n-1)!的逆元为n*n!^(mod-2)
    }
}

int C(int m, int n){
    if(n>=0&&m>=n){
        return a[m]*b[n]%mod*b[m-n]%mod;    // 两个阶层相乘后就要取mod防止溢出
    }else{
        return 0;
    }
}

        1>什么是逆元:如果一个线性同余方程ax 三 1(mod b),称x为 a mod b 的逆元;即一个数有逆元x,除以这个数a,相当于乘以x

        2>费马小定理:若p为质数,a为正整数,且a、p互质,则a^p-1 三 1 (mod p)

        3>C(m,n) = m! / (m-n)! * n!

3.完整代码

#include <bits/stdc++.h>
#define int long long 
using namespace std;

const int mod = 1e9+7,N = 1e6+10;
int a[N],b[N];

int qpow(int a, int b){
    int t = 1;
    int y = a;
    while(b){
        if(b&1){
            t = (t*y)%mod;
        }
        y = (y*y)%mod;
        b>>=1;
    }
    return t;
}


const int mod = 1e9+7,N = 1e6+10;
int a[N],b[N];

void init(){
    int n = 1e6;
    a[0]=1;
    b[0]=1;
    for(int i=1;i<=n;i++){
        a[i] = a[i-1]*i%mod;
    }
    b[n] = qpow(a[n],mod-2);
    for(int i=n-1;i>=1;i--){
        b[i] = b[i+1]*(i+1)%mod;
    }
}

int C(int m, int n){
    if(n>=0&&m>=n){
        return a[m]*b[n]%mod*b[m-n]%mod;
    }else{
        return 0;
    }
}

void solve(){
    int n,x,y,nx,ny;
    cin>>n>>x>>y;
    string s;
    cin>>s;
    int ctu=0,ctd=0,ctl=0,ctr=0;
    for(auto c:s){
        if(c=='U')ctu++;
        if(c=='D')ctd++;
        if(c=='L')ctl++;
        if(c=='R')ctr++;
    }
    if(x>0&&ctu<x){cout<<"NO"<<endl; return ;}
    if(x<0&&ctd<-x){cout<<"NO"<<endl; return ;}
    if(y>0&&ctr<y){cout<<"NO"<<endl; return ;}
    if(y<0&&ctl<-y){cout<<"NO"<<endl; return ;}
    cout<<"YES ";
    nx = x;
    ny = y;
    for(auto c:s){
        if(nx>0&&c=='U'){nx--,cout<<"U";}
        if(nx<0&&c=='D'){nx++,cout<<"D";}
        if(ny>0&&c=='R'){ny--,cout<<"R";}
        if(ny<0&&c=='L'){ny++,cout<<"L";}
    }
    int ansx=0,ansy=0;
    for(int i=0;i<=n;i++){
        ansx+=C(ctu,i)*C(ctd,ctu-x-i)%mod;
        ansy+=C(ctr,i)*C(ctl,ctr-y-i)%mod;
    }
    ansx%=mod;
    ansy%=mod;
    cout<<" "<<ansx*ansy%mod<<endl;
}

signed main(){
    init();
    int t;
    cin>>t;
    while(t--){
        solve();
    }
}

D.小红的差值构造 - easy+hard+extreme

https://ac.nowcoder.com/acm/contest/91072/D

1.思路       

        当l<=n的时候,让x和y在数组n的中心mid处,对称分布在mid的左右两侧时,f最小

        当l>n的时候,让x分布在中心mid处,y在x+l处,可使得,f最小

        在计算f的时候需要计算三个区间,即x的左侧,y的右侧和x、y之间的区间

        当l<=n时,x的左侧和y的右侧都是等差数列,直接计算即可。x、y之间的区间,元素个数为偶数时,就是两个等差数列,元素个数为奇数时,是中间元素+两个等差数列

        当l>n时,可以得出y一定是在n元素的右侧且x、y之间的元素都是距x更近,所以要计算的区间剩下x的左侧和x、y之间。x的左侧就是等差数列直接计算,x的右侧也是等差数列直接计算

2.函数

(1)计算等差数列前n项和(x可能在0处,因此x左侧元素值无需计算返回0)

int cal(int x){    
    if(x<=0){
        return 0;
    }
    return (1+x)*x/2;
}

(2)计算x、y之间元素和

int calmid(int x){    // 元素个数
    int mid = x/2+x%2;
    if(x%2!=0){
        return mid+2*cal(mid-1);
    }else{
        return 2*cal(mid);
    }
}

3.完整代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

int cal(int x){
    if(x<=0){
        return 0;
    }
    return (1+x)*x/2;
}

int calmid(int x){
    int mid = x/2+x%2;
    if(x%2!=0){
        return mid+2*cal(mid-1);
    }else{
        return 2*cal(mid);
    }
}

void solve(){
    int n,l;
    cin>>n>>l;
    int mid = n/2+n%2;
    if(n>=l){
        int x = mid - l/2;
        int y = x + l;
        cout<<x<<" "<<y<<" "<<calmid(y-x-1)+cal(x-1)+cal(n-y)<<endl;
    }else{
        int x = mid;
        int y = mid + l;
        cout<<x<<" "<<y<<" "<<cal(x-1)+cal(n-x)<<endl;
    }
}

signed main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值