10月集训test19

所以我来补上前一天的啦~
上题。

1.数集

其实原本是想到了用队列的。。。但是忘了可以分成两个队列,并且两个队列一定是严格单调递增的。。。。。
只是注意要去重。。这个不难,对比两个队列如今枚举这一位的大小即可,将小的那位往后移一位,大的那位不移就好了。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
using namespace std;

int a,n,t,two,three,rear;
long long t1,t2;
long long q[1000010];

int main()
{
    //freopen("blash.in","r",stdin);
    //freopen("blash.out","w",stdout);

    while(scanf("%d%d",&a,&n)!=EOF)
    {
        rear=2;
        q[1]=a;
        two=1;three=1;
        while(rear<=n)
        {
            t1=q[two]*2+1;
            t2=q[three]*3+1;
            t=min(t1,t2);
            if(t1<t2)
                two++;
            else
                three++;
            if(t==q[rear-1])
                continue;
            q[rear]=t;
            rear++;
        }
        printf("%lld\n",q[n]);
    }
    return 0;
}

2.序列操作

打暴力的话显然每次应该取最大的c[i]个。
正解用了一个神奇的贪心:先二分,二分出答案后判断可行不可行只考虑这样的贪心。先贪心取最开始前c[i]大的(不管后来是不是前c[i]大),如果不够,就往后取,扫一遍就可以了。。。。。

//80分暴力
#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define ll long long
int c[N],h[N],n,num[N],ma;

int main() {
    //freopen("sequence.in","r",stdin);
    //freopen("sequence.out","w",stdout);
    int m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&h[i]);
    for(int i=1;i<=m;i++) scanf("%d",&c[i]);
    for(int i=1;i<=n;i++) {
        num[h[i]]++;
        ma=max(ma,h[i]);
    }
    for(register int i=1;i<=m;++i) {
        int tot=0,pos=0;
        for(register int j=ma;j>=1;--j) {
            if(tot+num[j]>=c[i]) {
                pos=j+1;
                break;
            }
            tot+=num[j];
        }
        if(pos==0) {
            printf("%d",i-1);
            return 0;
        }
        int tmp=c[i]-tot;
        num[pos-1]-=tmp;
        num[pos-2]+=tmp;
        for(register int j=pos;j<=ma;++j) {
            num[j-1]+=num[j];
            num[j]=0;
        }
    }
    printf("%d",m);
}

3.图

题目说的很明确,是最小生成树。
正解。。。复杂的不要不要的,不过刻意暴力求LCA,暴力翻转边,也能AC掉这道题。
只上暴力。

//30分暴力,T掉了。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

struct node
{
    int u,v,w,y;
}bian[400010];
int n,q,a,b,m=0,x,k;
int f[100010];
long long ans;

inline int read()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-') f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i*f;
}

inline bool comp(const node &a,const node &b)
{
    return a.w<b.w;
}

inline int gf(int x)
{
    if(x==f[x])
        return x;
    f[x]=gf(f[x]);
    return f[x];
}

int main()
{
    //freopen("mst.in","r",stdin);
    //freopen("mst.out","w",stdout);

    n=read(),a=read(),b=read(),q=read();
    for(int i=1;i<=a;i++)
    {
        bian[++m].u=read();
        bian[m].v=read();
        bian[m].w=read();
        bian[m].y=1;
    }
    for(int i=1;i<=b;i++)
    {
        bian[++m].u=read();
        bian[m].v=read();
        bian[m].w=read();
        bian[m].y=0;
    }
    while(q--)
    {
        x=read();ans=0;k=0;
        for(int i=1;i<=m;i++)
            if(bian[i].y==1)
                bian[i].w+=x;
            else if(bian[i].y==0)
                bian[i].w-=x;
        sort(bian+1,bian+m+1,comp);
        for(int i=1;i<=n;i++)
            f[i]=i;
        for(int i=1;i<=m;i++)
        {
            if(gf(bian[i].u)!=gf(bian[i].v))
            {
                f[gf(bian[i].u)]=bian[i].v;
                ans+=bian[i].w;
                k++;
            }
            if(k==n-1)
                break;
        }
        cout<<ans<<endl;
        for(int i=1;i<=m;i++)
            if(bian[i].y==1)
                bian[i].w-=x;
            else if(bian[i].y==0)
                bian[i].w+=x;
    }
    return 0;
}

以上。
来自2017.11.6.

——我认为return 0,是一个时代的终结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值