博客总结第十周+牛客月赛

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了博客总结第十周+牛客月赛相关的知识,希望对你有一定的参考价值。

P1873 [COCI 2011/2012 #5] EKO / 砍树

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int a[maxn];
int n,m;

int main()
{
    cin>>n>>m;
    int l=0,r=0,mid;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        r=max(r,a[i]);
    }
    while(l<=r)
    {
        mid=(l+r)/2;
        ll s=0;
        for(int i=1;i<=n;i++)
            if(a[i]>mid)
            s+=a[i]-mid;
        if(s<m)
            r=mid-1;
        else
            l=mid+1;
    }
    cout<<r<<endl;
    return 0;
}

P1024 [NOIP2001 提高组] 一元三次方程求解
在二分中,一个题目关键部分对了,就算一些细节的地方处理的不好,也能ac。

#include <bits/stdc++.h>
using namespace std;
double a,b,c,d;
double cir(double x)
{
    return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
    cin>>a>>b>>c>>d;
    double l,r,x1,x2,mid;
    int s=0;
    for(int i=-100;i<100;i++)
    {
        l=i;r=i+1;
        x1=cir(l);x2=cir(r);
        if(!x1)
        {
            printf("%.2f ",l);
            s++;
        }
        if(x1*x2<0)
        {
            while(l+0.001<=r)
            {
                mid=(l+r)/2;
                if(cir(mid)*cir(r)<0)
                    l=mid;
                else
                    r=mid;
            }
            printf("%.2f ",l);
            s++;
        }
        if(s==3) break;
    }
    return 0;
}

B. Odd Grasshopper
一道分奇偶的水题,找清除规律就好。

#include <bits/stdc++.h>
using namespace std;
long long x,n;
int main()
{
    freopen("in.txt","r",stdin);
    int t;cin>>t;
    while(t--)
    {
        long long ans;
        cin>>x>>n;
        if(x%2==0)
        {
            if(n%4==1)
                ans=x-n;
            else if(n%4==2)
                ans=x+1;
            else if(n%4==3)
                ans=x+n+1;
            else
                ans=x;
        }
        else
        {
            if(n%4==1)
                ans=x+n;
            else if(n%4==2)
                ans=x-1;
            else if(n%4==3)
                ans=x-(n+1);
            else
                ans=x;
        }
        cout<<ans<<endl;
    }
    return 0;
}

C. Minimum Extraction

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int a[maxn];
int main()
{
    freopen("in.txt","r",stdin);
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        if(n==1){
            cout<<a[1]<<endl;
            continue;
        }
        sort(a+1,a+n+1);
        int ans=-INT_MAX;
        for(int i=2;i<=n;i++)
        {
            ans=max(ans,a[i]-a[i-1]);
        }
        ans=max(a[1],ans);
        cout<<ans<<endl;
    }
    return 0;
}

*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

小白月赛 40

牛客 分组
还好最近看了一点二分。
刚开始想用map来做的,结果发现map的遍历不太会,索性又开了个数组直接记录。二分对边数据的临界值要好好考虑,一般会没输出,或者答案大于1或者小于1,本题我慢慢试出来了,没太多想。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;
int a[maxn];
int b[maxn];
int go(int mid)
{
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(b[i])
        {
            if(b[i]%mid==0)
                ans+=b[i]/mid;
            else
                ans+=b[i]/mid+1;
        }
    }
    if(ans<=m) return 1;
    else return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    cin>>n>>m;
    int ans=1;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        b[a[i]]++;
    }
    int k=1;
    sort(a+1,a+n+1);
    for(int i=2;i<=n;i++)
    {
        if(a[i]!=a[i-1])
            k++;
    }
    int l=0,r=n+1;
    if(k<=m)
    {
        while(l<r)
        {
        int mid=(l+r)/2;
        if(go(mid))
            r=mid;
        else
            l=mid+1;
        }
        cout<<r<<endl;
    }
    else
    {
        cout<<-1<<endl;
    }
    return 0;
}

受不了了这一题,明明不难,可就是通不过。刚开始题意理解不了,然后有把规律找错,最后每次都超时,换了快读,还是超时,最后才发现必须要用printf进行输出。蠢的呀!
A—数字游戏

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
string calc(int x)
{
    if(x == 0) return "0";
    string ans = "";
    while(x){
        ans += ('0' + x % 2);
        x >>= 1;
    }
    reverse(ans.begin(), ans.end());
    return ans;
}
ll read()
{
	char c=getchar();
	ll ds=0,fs=1;
	while (c<'0'||'9'<c) {if (c=='-') fs=-1;c=getchar();}
	while (c>='0'&&c<='9') ds=(ds<<3)+(ds<<1)+c-48,c=getchar();
	return ds*fs;
}

int main()
{
    int t;cin>>t;
    while(t--)
    {
        ll x,ans=0;
        x=read();
        string s=calc(x);
        for(int i=0;i<s.length();i++)
        {
            if(s[i]=='1')
                ans++;
        }
        int k=s.length()-1;
        if(x%2)
        {
            if(ans%2)
                ans=2*ans-1;
            else
                ans=2*ans-2;
        }
        else
        {
            if(ans%2)
                ans=2*ans+1;
            else
                ans=2*ans;
        }
        printf("%d\\n",ans);
    }
    return 0;
}

B.跳跳跳
常规的区间dp,如果我还是去年刚学完区间dp的水平,肯定能很快做出来。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=4005;
int n,a[maxn],f[maxn][maxn];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        a[n+i]=a[i];
    }
    for(int i=1;i<=2*n;i++) //默认为第一次跳跃
    {
        f[i][i]=a[i]*1;
    }
    for(int len=2;len<=n;len++) //跳跃次数
    {
        for(int i=1,j=i+len-1;j<=2*n;i++,j++)
        {
            f[i][j]=max(f[i+1][j]+len*a[i],f[i][j-1]+len*a[j]);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        ans=max(ans,f[i][i+n-1]);
    }
    cout<<ans<<endl;
    return 0;
}

C 数字匹配
1.首先判断出2000以内的双重for循环不会超时
2.关键在于掌握substr从下标为i的位置开始截取j位。双重for循环找到即返回1。

#include <bits/stdc++.h>
using namespace std;
int n,k;
string calc(int x)
{
    if(x == 0) return "0";
    string ans = "";
    while(x){
        ans += ('0' + x % 2); //转换类型
        x >>= 1;
    }
    reverse(ans.begin(), ans.end());
    return ans;
}
int check(int x,int y)
{
    string s=calc(x);
    string t=calc(y);
    int s1 = s.size();
    int s2 = t.size();
    //substr用法: s.substr(i,j)表示从下标为i的位置开始截取j位
    for (int i = 0; i + k <= s1; ++i)
        for (int j = 0; j + k <= s2; ++j)
            if (s.substr(i, k) == t.substr(j, k))
                return 1;
    return 0;
}
int main()
{
    cin>>n>>k;
    int ans=0;
    for(int i=1;i<n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(check(i,j))
                ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

I 体操队形
(第一次坐到全排列的题目,根本没想到这个方法)
将b数组进行全排列,再用vis数组进行标记1(本质就是确定这个数能不能放在这个位置上),一组数没有被重复标记,则成立。

#include <bits/stdc++.h>

using namespace std;
int n;
int a[15],b[15],vis[15];
int main()
{
    cin>>n;
    int total=1,ans=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        b[i]=i;
        total*=i;
    }
    for(int i=1;i<=total;i++)
    {
        int f=0;
        memset以上是关于博客总结第十周+牛客月赛的主要内容,如果未能解决你的问题,请参考以下文章

牛客月赛42

牛客月赛42题解完结

牛客月赛46部分题解

8/12 最小表示法+牛客月赛

牛客月赛:走出迷宫(Java)

牛客月赛60 F.被抓住的小竹(数学&推式子)