2024年河南省ccpc赛后总结

大二,第二次参加ccpc线下比赛,没有发挥好,思路有些乱,没有静下心去思考,到最后无脑硬猜结论,导致只与队友ac三道题,获得省赛铜牌。

开始两分钟的时候看有人把签到题F过了,就先去敲签到,怕罚时还多测试了几组数据,交一发过了,于是跟队友开始写b题,一开始以为是个dp,我就想先敲状态dp的代码,但是发现初始状态跟转移方程有些难推,于是考虑贪心解法,当时我有个思路,取后缀min,将把金币留给后面小的花费时再购买,于是先开了个数组,但是队友让我用map存下标位置,一开始不是很理解,但是听完他讲完之后发现思路大致相同,就是还在自己的思维当中,不会队友的实现过程,就给队友操作了,敲出来之后我们还是测了几发自己出的数据,发现没问题就交了,也是一发过(赛后用自己的思路写发现也是能过的,不过比赛中我觉得还是要综合队友思路,合作将思维漏洞缩到最小),第三题写的J题,看题目只有五位数,跑一个全排列next_permutation肯定能暴力过的,但是队友发现了其中的性质,也算是本题的特殊解法吧,算是将o(n*5!)优化到了o(n),不过两种都能过,注意到前导零这个小细节处理一下也是一发就过,到此为止三道题都是一次过的,没有任何罚时,解完之后大概在国铜的铜首(在当时一个小时以内ac三道题无罚时已经是咱学校最好的成绩了)。但后面的四个小时我们一道题都没过!!!H取模忘记每两个数相乘都要取模,爆了long long,M我作为队长甚至想投机取巧猜结论,压根没去想二分!!!这是我觉得本次比赛我最大的失误。而且L的简单线性dp也没有去写(当时转移方程已经推出来了,就是卡在H、M两题上,压根没去心态写!!!),最后遗憾只拿省铜。

总的来说,这次比赛证明我的实践能力太弱,主要的锅在我身上,没有一眼看出M是个二分,总想贪心猜结论(被M卡了两个多小时)而且没有及时弃题去写L的dp跟H的模拟。队伍之间的配合也太少,应该在一起多讨论讨论,商量分工。

一开始跟队友分别找题,本来想先写b题,但两分钟看榜单有人把f题过了,于是我们就先去写了f973b2b080926404f95304937a49f5322.png

签到题,就照着题意去判断就能ac

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
void solve()
{
    int n;cin>>n;
    int ans=0;
    for(int i=0;i<n;i++)
    {
        string s;cin>>s;
        if(s.size()==5&&set(s.begin(),s.begin()+4).size()==4&&s[2]==s[4])
        ans++;
    }
    cout<<ans;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t=1;
    //cin>>t;
    while(t--)solve();
    return 0;
}

写完签到题,我们又继续写b题,一开始想到这题类似于acwing里面的股票购买类型的题,那道题有dp和贪心两种解法,这题本来一开始也想写个dp,但是发现初状态并不好表示,于是写的是贪心解法,先写一个关于c[i]的后缀min,把金币留给后面小的花费时再购买。

52e6ec1c91b64680b1cdf7152eed138b.png

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
void solve()
{
    int n;cin>>n;
    vector<int>c(n);
    for(int i=0;i<n;i++)cin>>c[i];
    for(int i=n-2;i>=0;i--)
    {
        c[i]=min(c[i],c[i+1]);
    }
    int cnt=0;
    int ans=0;
    for(int i=0;i<n;i++)
    {
        cnt++;
        if(cnt>=c[i])
        {
            cnt-=c[i];
            ans++;
        }
    }
    cout<<ans;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t=1;
    //cin>>t;
    while(t--)solve();
    return 0;
}

后面看j题过的人数也比较多,我们跟榜做题。这题本来看只有五位数,想while_nextpermutation()直接暴力跑完的,但是发现了对于五位数有这样的性质:只要存在0,2,4,6,8,5这六个数字其中之一,把其放在末尾的位置,必定就是合数,而剩下的1,3,7,9只有四位数字,不够组成五位数,所以至少有0,2,4,6,8,5这六个数其中之一,因此这道题不存在-1这种情况,有了换位置的思路,只需要处理一下前导零就行了,方法也比较简单,判断换位后的s[0]是否为0,是则swap(s[0],s[1])就可以了。

2c76de8dd2e2464daf6df7cfa1dd9074.png

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
void solve()
{
    string s;cin>>s;
    int pos=0;
    string ans="";
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='0'||s[i]=='2'||s[i]=='4'||s[i]=='6'||s[i]=='8'||s[i]=='5')
        {
            pos=i;
            break;
        }
    }
    for(int i=0;i<s.size();i++)
    {
        if(i!=pos)ans+=s[i];
    }
    ans+=s[pos];
    if(ans[0]=='0')swap(ans[0],ans[1]);
    cout<<ans<<"\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t=1;
    cin>>t;
    while(t--)solve();
    return 0;
}

比赛时只ac了这三道题,M、H、Ldebug半天均未调试出来

M需要将每个a[i]变为x,并满足式子:|ai − x| ≤ k × bi

通过数学公式变换可以推出a[i]-k*b[i]<=x<=a[i]+k*b[i],k越大x的范围也越大,可以用二分来判断这个x的区间是否存在。

48971c19b2ea49acbaf2d9154b77d18a.png

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int N=3e5+10;
int a[N],b[N];
int n;
bool check(int k)
{
    int l=-1e18,r=1e18;
    for(int i=0;i<n;i++)
    {
        l=max(l,a[i]-k*b[i]);
        r=min(r,a[i]+k*b[i]);
    }
    return l<=r;
}
void solve()
{
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int i=0;i<n;i++)cin>>b[i];
    int l=0,r=1e9;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout<<l<<"\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t=1;
    cin>>t;
    while(t--)solve();
    return 0;
}

H题就是顺着模拟,遇到-1取出已经存入的最小值,并记录,后续的-1如果取出一个数比上次取出的数要小,直接输出0.

b89c270580ca4369a9265d8350a9610a.png

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int N=2e5+10,mod=998244353;
int a[N*2];
int n;
int qmi(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
void solve()
{
    cin>>n;
    for(int i=1;i<=n*2;i++)cin>>a[i];
    priority_queue<int,vector<int>,greater<int>>q;
    vector<int>mp(n+1,0);
    int l=-1;
    int ans=1;
    for(int i=1;i<=n*2;i++)
    {
        if(a[i]!=-1)
        {
            if(a[i]<l)
            {
                cout<<0;
                return;
            }
            else
            {
                q.push(a[i]);
                mp[a[i]]++;
            }
        }
        else
        {
            int tt=q.top();
            l=max(l,tt);
            ans=(ans%mod*mp[tt]%mod*qmi((int)q.size(),mod-2))%mod;
            mp[tt]--;
            q.pop();
        }
    }
    cout<<ans;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t=1;
    //cin>>t;
    while(t--)solve();
    return 0;
}

L题,线性dp,dp[i]为解决了前i行bug的最少时间,状态转移方程为dp[a[i]]=min(dp[a[i]],dp[a[j]]+(i-j)*(i-j)*(i-j)*(i-j)+a[i])。

4b935a5d3ace4ba6827145dd3c5f0b1f.png

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int N=2e5+10;
int a[N],dp[N];
int n,m;
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)cin>>a[i];
    memset(dp,0x7f,sizeof dp);
    dp[0]=0;
    for(int i=1;i<=m;i++)
    {
        for(int j=i-1;j>=max(0LL,i-(int)sqrt(n));j--)
        {
            dp[a[i]]=min(dp[a[i]],dp[a[j]]+(i-j)*(i-j)*(i-j)*(i-j)+a[i]);
        }
    }
    cout<<dp[a[m]];
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t=1;
    //cin>>t;
    while(t--)solve();
    return 0;
}

  • 15
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值