2018icpc青岛网络赛

本文解析了A题最大连续数问题,H题通过动态规划解决红绿灯行走问题,J题模拟按钮操作计数问题,以及K题二进制位运算问题。文章提供了详细的算法思路和C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A题

大水题,求最大连续数多少个和最小的最大连续数多少个。

最多连续个数,毫无疑问就是perfect的个数全都连续才最多。注意最少的个数是要平均分,比如一共8个其中6个perfect,分成2,2,2连续的个数才是最少的,如果有比2小的就会有比2大的,那么最小的最大的连续数就>2了

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        cout<<m<<' ';
        if(m==0)             //特殊情况连续数为0
            cout<<'0'<<endl;
        else if(n>=2*m-1)
            cout<<'1'<<endl;
        else if(m==m+1)
            cout<<(m+1)/2<<endl;
        else if(n>m)
        {
            double mm=1.0*n/(n-m+1))>n/(n-m+1)?n/(n-m+1)+1:n/(n-m+1);//平分m, 一共(n-m+1)个位置
                                                                    //类似于分苹果,只能整个分
                                                                    
            cout<<mm<<endl;
        }
        else if(n==m)
            cout<<m<<endl;
    }
}

也可以这样想

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        cout<<m<<' ';
        if(m==0)
            cout<<'0'<<endl;  //特殊情况连续数为0
        else
            cout<<n/(n-m+1)<<endl; // 一共(n-m+1)位置,n平分成(n-m+1)份
                                    //一份中m被平分了多少
    }
}

H题

可以dp,可以区间修改,可以前缀和。

步数为偶数次时与初始状态相同,奇数次时与初始状态相反。

用区间修改和前缀和比较好想,每过一个点修改区间里的步数,区间修改线段树或树状数组维护,红灯步数+2,绿灯步数+1,利用奇偶数步判断状态。

dp:  样例3:11010

 

dp[3]所包含的所有时间为 t[0,1],t[1,2],t[2,3],t[1,2],t[2,3]和t[2,3] 即 t[0,2]+t[2,3],t[1,2]+t[2,3]和t[2,3]

其中 t[0,2],t[1,2]即dp[2],第三个t[2,3]就是判断第二个灯的状态是s[2]。

设change(i,j) 表示从i处到j处红绿灯变化的总次数, 计算第一个t[2,3]需要知道change[0,2], 如果change[0,2]是偶数,则计算t[2,3]时原先的红绿灯状态不变,反之,改变状态。 计算第二个t[2,3]亦是如此,需要知道change[1,2]。难点就在于change[0,2]与change[1,2]。

计算容易发现change[0,2]=3,change[1,2]=1;

 且通过计算其他的change[l,m](i<m)可以发现,change[0,m]与change[1,m],..change[m-1,m]同奇偶
此时易得后前个t[2,3]的值是一样的, 都和change[1,2]的奇偶以及s[2]状态有关故后两个t[2,3]的和x为

if(change[1,2]为偶)  

      x=2*(s[2]=='1'?1:2); 

else

     x=2*(s[2]=='1'?2:1);

因为如果s[1]==1则change[1,2]=1,如果是s[1]=0,则change[1,2]=0,即是s[i]奇change[i,i+1]奇,反之亦然。

由伪代码可以得到,1->2点  s[1]奇s[2]奇,步数=2;s[1]偶s[2]偶,步数=2;s[1]奇s[2]偶,步数=1;s[1]偶[2]奇,步数=1;

所以

(i-1)->i的步数= s[i-1]==s[i]?2:1;

if-else语句合并为 

 x=2*(s[i-1]==s[i]?2:1);

由此得dp[i]

dp[i]=dp[i-1]+(i-1)*((s[i]==s[i-1])?2:1)+((s[i]=='1')?1:2);

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+5;
long long dp[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        string s;
        cin>>s;
        s='0'+s;         //s[i]下标从0开始,而规律是从1开始,所以在前面补一位
        memset(dp,0,sizeof dp);
        dp[1]=(s[1]=='1'?1:2); //根据第一个灯状态,得dp[1]
        for(int i=2;i<s.length();i++)
        {
           dp[i]=dp[i-1]+(i-1)*((s[i]==s[i-1])?2:1)+((s[i]=='1')?1:2);
        }
        long long sum=0;
        for(int i=1;i<s.length();i++)
        {
           // cout<<"dp"<<i<<": "<<dp[i]<<endl;
            sum+=dp[i];
        }
        cout<<sum<<endl;
    }
}

J题

两个人B,D按 按钮,灯不亮,按一下变亮,灯亮着,计数器+1,按按钮的时间点分别是a,c的整数倍,若时间点相同,则B先D后,按下按钮后倒计时器变为v+0.5(不管按钮前是多少)。

这个题可以模拟,可能因为我太弱惹2333,模拟总是超时(;´ ༎ຶ  Д ༎ຶ` ),然后就总数减去不ok的数得到ok的数......

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 2e6+5;
LL f[N];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        LL v, t;
        int a, b, c, d;
        scanf("%d%d%d%d%lld%lld", &a, &b, &c, &d, &v, &t);
        int n=0;
        for(int i=0;i<a;i++)
        {
            f[n++] = 1LL*i*c;
        }

        for(int i=0;i<c;i++)
        {
            f[n++] = 1LL*i*a;
        }
        LL per = 1LL*a*c;
        sort(f, f+n); f[n++] = per;
        for(int i=0;i<=n;i++)
            cout<<"f"<<i<<":"<<f[i]<<' ';
        cout<<endl;
        LL ans = (t+a)/a*b +(t+c)/c*d ; ///如果按下就+1,不算开灯
        ans-=1;                         ///减去0时按下开灯
        //cout<<(t+a)/a*b<<' '<<(t+c)/c*d<<endl;
        LL nx = 0;                      ///开灯次数
        for(int i=1;i<n;i++)
        {
            if(f[i-1]+v+0.5<f[i])        ///如果f[i-1]+v+0.5<f[i],要开灯
            {
                ++nx;
            }
        }
        LL tt = t/per;                   ///a*c一个周期,t占多少个周期
        ans-=nx*tt;                      ///减去周期数*一个周期要开灯的数
        t%=per;                          ///如果不满一个周期
        for(int i=1;i<n;i++)
        {
            if(f[i-1]+v+0.5<f[i] && f[i]<=t)  
            {
                --ans;
            }
        }
        printf("%lld\n", ans);
    }
}

 

 

K题

两个数的异或小于这两个数,即看二进制最高位是否相同,相同的话肯定小于这两个数

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 32;
int ans[N];
int main() 
{
    int T;
    scanf("%d", &T);
    while(T--)     
    {
        int n;
        scanf("%d", &n);
        memset(ans, 0, sizeof(ans));
        int x;
        while(n--)
         {
            scanf("%d", &x);
            int num = 0;
            while(x>0)
            {
                x>>=1;
                ++num;
            }
            ++ans[num];
        }
       /* for(int i=0;i<N;i++)
        {
            cout<<ans[i]<<' ';
        }*/
        printf("\n%d\n", *max_element(ans, ans+N));
    }
}

 

### 关于2024 ICPC网络预选的信息 #### 参规则 国际大学生程序设计竞ICPC)作为一项全球性的事,其参规则通常保持一定的稳定性。根据以往的经验和惯例[^1],每支参队伍由三名队员组成,他们需在同一台计算机上合作完成一系列算法问题的解答。比期间不允许使用任何外部资源或工具书,仅能依赖团队成员的知识储备以及现场提供的少量参考资料。 对于具体的2024年ICPC网络预选而言,虽然官方尚未发布详细的最新规定,但可以推测基本框架不会发生显著变化。例如,在线形式可能继续沿用近年来因疫情而普及的方式;同时也会严格监控作弊行为以维护公平竞争环境[^2]。 #### 时间安排 关于2024年的具体时间表目前还没有确切消息公布出来。然而按照传统模式来看,整个流程一般会经历以下几个阶段: - **报名期**:预计会在年初开放注册通道供各高校提交候选名单。 - **区域选拔/网络挑战**:这通常是多轮次举行,覆盖不同大洲和地区的时间段以便更多选手参与进来体验实战氛围并争取晋级机会。 - **全球总决准备阶段**:成功突围进入最终环节者将获得额外培训指导来提升实力迎接巅峰对决时刻。 以下是基于历史数据猜测的一个大致日程示例(请注意实际日期应参照官方通知为准): | 阶段 | 开始日期 | 结束日期 | |--------------------|---------------|----------------| | 报名截止 | 2024-02-15 | | | 初步筛选结果公告 | | 2024-03-01 | | 第一轮网络资格 | 2024-03-10 | 2024-03-12 | | 复活 | 2024-04-07 | 2024-04-09 | | 半决分区 | 各区自行决定 | 各区自行决定 | #### 题目解析 由于正式试题还未出炉之前无法提供针对性分析,不过可以根据往届经典案例来进行一些通用技巧分享: ```python def example_problem(): """ 假设有一道简单的字符串匹配问题. 给定两个长度不超过1e6 的字符串S 和T(S >= T),判断是否存在子串使得两者完全一致. 如果存在返回True;否则False. """ from collections import defaultdict def kmp_preprocess(pattern): lps = [0]*len(pattern) j=0;i=1; while i<len(pattern): if pattern[i]==pattern[j]: lps[i]=j+1;j+=1;i+=1; elif j!=0: j=lps[j-1]; else : lps[i]=0;i+=1 return lps; s="abcde";t="bcd"; lps=kmp_preprocess(t); q=[]; res=False; for char in s: while(q and (not t[len(q)]==char)): last=len(q)-lps[-1];q=q[:last]; if not q or t[len(q)]==char:q.append(char); if ''.join(q)==t:res=True;break; print(res) example_problem() ``` 上述代码片段展示了一个利用KMP算法解决字符串查找的经典方法之一。当然这只是众多可能性中的很小一部分而已。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值