2024ccpc中国郑州

题目链接:Dashboard - 2024 National Invitational of CCPC (Zhengzhou), 2024 CCPC Henan Provincial Collegiate Programming Contest - Codeforces


//Solve函数结合末尾模板

F.优秀字符串

题意:

优秀字符串:长度为5,第三个字符与第五个字符相同,S 的前四个字符互不相同。

给定n个字符串,判断优秀字符串数量。

思路:

先判断长度,在判断第三个和第五个字符,for循环判断前四个字符是否相同

Solved:

int solve()
{
    string s;cin>>s;
    int len=s.size();
    if(len!=5) return 0;
    if(s[2]!=s[4]) return 0;
    for(int i=0;i<=3;i++){
        for(int j=i+1;j<=3;j++)
        if(s[i]==s[j]) return 0;
    }
    return 1;
}
//	while(n--){
//      if(solve()==1){
//          sum++;
//      }
//  }
//  cout<<sum;

J.排列与合数

题意:

给定一个n,判断是否为合数,if合数就输出,else if重新排序为合数后输出,else -1。

保证n的各个数位互不相同。

合数:除了1和他本身,还能被其他数整除。

思路:

n的各个数位互不相同,可得出末尾偶数0,2,4,6,8均为2的倍数,末尾为5为5的倍数,此时还剩4个数,n保证5位,所以排序后一定可以构成合数。

直接判断末尾是不是0,2,4,6,8,5,是直接输出,不是就从前四位中找一个0,2,4,6,8,5与末尾交换位置即可。

不用考虑前导0,如果末尾有0直接输出,题目给出n不含前导0,交换0只会到末尾

Solved:

void solve()
{
    string s;cin>>s;
    if(s[4]=='0'||s[4]=='2'||s[4]=='4'||s[4]=='6'||s[4]=='8'||s[4]=='5'){
        cout<<s<<endl; return;
    }
    else{
            for(int i=0;i<=3;i++){
                if(s[i]=='0'||s[i]=='2'||s[i]=='4'||s[i]=='6'||s[i]=='8'||s[i]=='5'){
                    swap(s[i],s[4]);
                    break;
                }
            }
            cout<<s<<endl; return;
    }
}

B. 扫雷 1

题意:

每个回合给一金币(money),并给出一个探测仪价格(cost),可在该回合买探测器,求一轮游戏最多获得多少探测器。

思路

定义结构体将cost和money连接,按照cost升序排序,在每个最低cost时买入探测器,更新每轮金币(此时我将每轮花费存入t,cnt为上一轮剩余的钱数,每轮money=money-t+cnt更新,并归零cnt),如果可以买入探测器,就在ans+本轮个数。

Solved:

const int N=2e5+10;

struct st
{
    int c,m;//c:cost,探测器价格,m:money本轮金币数
}a[N];

int cmp(st p,st q)
{
    if(p.c<q.c) return 1;
    return 0;
}

signed solve()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i].c;
        a[i].m=i;
    }
    sort(a+1,a+1+n,cmp);
    // for(int i=1;i<=n;i++){
    //     cout<<a[i].c<<" "<<a[i].m<<endl;
    // }
    int ans=0;//购买总量
    int cnt=0;//上一轮购买完剩余金币
    int t=0;//每次购买后的花费
    for(int i=1;i<=n;i++){
        a[i].m=a[i].m-t+cnt;//利用t和cnt更新每轮剩余金币数
        cnt=0;//重置余数
        if(a[i].m>=a[i].c)//如果本轮money>=cost可以购买
        {
            ans+=a[i].m/a[i].c;//买
            cnt+=a[i].m%a[i].c;//剩余金币
            t+=a[i].m/a[i].c*a[i].c;//更新总花费
        }
    }
    cout<<ans; return;

A.Once In My Life

题意:

幸运数:数位包含1~9,并且至少包含两位d。

给定一个正整数n,希望找到一个k使得n*k为幸运数。

思路:

根据数据范围n<1e8,longlong 19位,所以可以先构造kk=1234567890+d,并将n加到kk的后面去构造n的倍数找k(如果不加n直接除n,可能使1234567890+d(幸运数序列)造成影响)。

Solved:

void solve()
{
    int n,d;cin>>n>>d;
    int kk=1234567890+d;//构造幸运数序列
    int len=log10(n)+1;//int len=to_string(n).size();
    kk*=pow(10,len);//将n+到k后
    kk+=n;
    cout<<kk/n<<endl;//输出k
}

M.有效算法

题意:

给出ai,bi

ai可以变成满足|ai−x|≤k×bi的任意整数x,求出最小的k。

去绝对值后

ai-x<=k * bi ,ai-x>=-k * bi。

题目中数据范围很大,因此k不能从1~n按顺序找,应该用二分

找到k后验证x的取值范围,x>=ai-k * bi ,x<=ai+k * bi.

遍历a和b数组

如果左端点的最大值大于右端点的最小值,则k不成立,left=mid+1(在mid右侧找k)

如果遍历完k成立,则 right=mid (在mid左侧找k)

Solved:

const int N=3e5+10;
int a[N],b[N];
int n;
int num(int k)
{
    int mx=INT_MIN,mi=INT_MAX;
    for(int i=1;i<=n;i++){
        mx=max(mx,a[i]-k*b[i]);
        mi=min(mi,a[i]+k*b[i]);
        if(mx>mi)
        return 0;
    }
    return 1;
}
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++){
        cin>>b[i];
    }
    int l=0,r=1e9,mid;
    while(l<r){
        mid=l+r>>1;
        if(num(mid)==1){
            r=mid;
        }
        else{
            l=mid+1;
        }

    }
    cout<<l<<endl;
}

H.随机栈

题意:

有一个随机的栈,给出数字如果-1则从栈中随机取出数字,否则将数字存入栈中。

求从一个栈中顺序取出的数字排成升序的概率,要求结果逆元

费马小定理:如果mod p,p为一个质数,b的p-2次方就是b的乘法逆元

思路:

求排成升序的概率,可以算出每次都取栈中最小数字的概率,取出最小数字可用大根堆实现,开book数组存最小数字在大根堆中出现次数,本次取出概率即为出现次数/大根堆总个数

const int mod=998244353;
const int N=2e5+10;
int a[N],book[N];
int qmf(int s,int y)
{
    int res=1;
    while(y){
        if(y&1){
            res=res*s%mod;
        }
        s=s*s%mod;
        y/=2;
    }
    return res;
}
void solve()
{
    priority_queue<int,vector<int>,greater<int>> q;
    int n;cin>>n;
    int mx=0;
    int fz=1,fm=1;
    for(int i=1;i<=2*n;i++){
        int x;cin>>x;
        if(x!=-1){
            q.push(x);
            book[x]++;
        }
        else{
            int t=q.top();
            if(t<mx){
                cout<<"0"<<endl;
                return ;
            }
            fz=fz*book[t]%mod;
            fm=fm*q.size()%mod;
            book[t]--;
            q.pop();
            mx=t;
        }
    }
    int ans=qmf(fz,mod-2)*qmf(fm,mod-2)%mod;
    cout<<ans;
}

模板

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

void solve()
{
    
}
signed main()
{
    std::ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n;cin>>n;
    while(n--){
        solve();
    }
    return 0;
}
  • 38
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值