2018icpc青岛网络赛

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));
    }
}

猜你喜欢

转载自blog.csdn.net/QLU_minoz/article/details/82749443