hgoi#20190507

T1-Anastasia and pebbles

安娜斯塔西娅喜欢去乌日扬迪安中央公园散步。 但她对简单的散步不感兴趣,于是她开始收集公园里的鹅卵石。
一开始,她决定收集所有她能在公园里找到的鹅卵石。
她只有两个口袋。 她能在每个口袋里同时放最多k个鹅卵石。第i种鹅卵石有w[i]个。 安娜斯塔西娅很有责任感,所以她从不把不同类型的鹅卵石混在一个口袋里。 然而,她可以把不同种类的鹅卵石放在不同的口袋。
不幸的是,她不能把所有的时间都花在收集鹅卵石上,所以她每天只能从公园里收集一次鹅卵石。
考虑到安娜斯塔西娅不能把不同类型的鹅卵石放在同一个口袋里,请帮助她找到收集乌日扬甸中央公园所有鹅卵石所需的最短天数。

解法

显然的贪心,一个口袋放满最优,就扫一边就可以了qwq

ac代码

#include<bits/stdc++.h>
using namespace std;
int n,k,x,ans;
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",&x),ans+=x/k+(x%k?1:0);
    printf("%d\n",(ans+1)/2);
    return 0;
}

T2-Masha and geometric depression

给你一个等比数列,首项为b1,公比为q,现在Masha在黑板上从首项开始书写这个等比数列,直到数列某项的绝对值大于l,给定m个整数,若该等比数列中的某项等同于这m个整数,则不会被写出。
问Masha会写出多少个数字?如果她会写出无穷多个数字,输出inf

解法

这道题太毒瘤了,有一种做法是纯模拟,当答案大于40时一定是inf,因为超出了上界
考试的时候没想到,就特判吧。。。

ac代码

#include<bits/stdc++.h>
using namespace std;
int b1,q,l,m,x,ans;
long long b;
map<int,bool>mp;
int main()
{
    scanf("%d%d%d%d",&b1,&q,&l,&m);
    for(int i=1;i<=m;i++)scanf("%d",&x),mp[x]=1;
    if(q==1){if(mp[b1]||abs(b1)>l)puts("0");else puts("inf");}
    else if(q==0)
    {
        if(abs(b1)<=l)
        {
            if(mp[0])
            {
                if(mp[b1])puts("0");
                else puts("1");
            }
            else puts("inf");
        }
        else puts("0");
    }
    else if(q==-1){if((mp[b1]&&mp[-b1])||abs(b1)>l)puts("0");else puts("inf");}
    else if(b1==0){if(mp[b1])puts("0");else puts("inf");}
    else
    {
        b=b1;
        while(abs(b)<=l){if(!mp[b])ans++;b=b*q;}
        printf("%d\n",ans);
    }
    return 0;
}

T3-Functions again

定义一个函数,函数如下:f[l,r]=\sum_{i=l}^{r-1}|a_i-a_{i-1}|\times(-1)^{i-l}
|x|表示x的绝对值。现在给你一个函数,请取恰当的l,r使f值最大,请输出最大的f值

解法

先把差分数组都求出来,同机房大佬都是O(n)动规做的,好像是最大子串和
我呢,菜的要死,只能nlogn做,用一个堆和链表来维护,每次找出最小的点,把它设为负,合并两边的,将三个点合并成一个点,在途中统计一下最大的答案

ac代码

#include<bits/stdc++.h>
using namespace std;
int n,l,r,del[100010],ll[100010],rr[100010];
long long a[100010],ans=0;
struct node{int num;bool operator<(const node&x)const{return a[num]>a[x.num];}};
priority_queue<node>q;
int main()
{
    scanf("%d",&n),l=1,r=n-1;
    for(int i=1;i<=n;i++)cin >> a[i];
    for(int i=1;i<n;i++)a[i]=abs(a[i]-a[i+1]),q.push({i}),ll[i]=i-1,rr[i]=i+1;
    while(!q.empty()&&l<=r)
    {
        while(l<=r&&del[l])l++;
        while(l<=r&&del[r])r--;
        node u=q.top();
        q.pop(),ans=max(ans,a[u.num]);
        if(del[u.num])continue;
        if(u.num==l)
        {
            del[l]=1,ll[rr[l]]=0;
            while(l<=r&&del[l])l++;
            continue;
        }
        if(u.num==r)
        {
            del[r]=1,rr[ll[r]]=0;
            while(l<=r&&del[r])r--;
            continue;
        }
        a[u.num]=a[ll[u.num]]+a[rr[u.num]]-a[u.num],del[ll[u.num]]=del[rr[u.num]]=1;
        ll[u.num]=ll[ll[u.num]],rr[u.num]=rr[rr[u.num]],rr[ll[u.num]]=ll[rr[u.num]]=u.num;
        q.push(u);
    }
    cout << ans << endl;
    return 0;
}

T4-Weird journey

总共有n个节点,m条路径,要求其中m-2条路径走两遍,剩下2条路径仅走一遍,问不同的路径总数有多少,如果仅走一遍的两条边不同则将这两条路径视为不同。

解法

所有无向边建两遍,一定是欧拉回路,现在要删去两条不同的边,使其还是欧拉回路或欧拉路径
那就只需要分类讨论了,只有0或2个度为奇数的点,只有三种情况:
删2个自环,删1个自环和1条边,删2条有公共点的边
乘法原理乱搞一下就可以了

ac代码

#include<bits/stdc++.h>
struct node{int to,next;}e[2000010];
int n,m,x,y,cnt,ss,head[1000010],f[1000010],h[1000010],s[1000010],d[1000010],t;
bool vis[1000010];
long long ans;
void add(){e[++cnt]={y,head[x]};head[x]=cnt,e[++cnt]={x,head[y]},head[y]=cnt;}
void dfs(int u)
{
    cnt+=d[u],t+=s[u],vis[u]=1,ans+=1ll*d[u]*(d[u]-1)/2;
    for(int i=head[u];i;i=e[i].next)if(!vis[e[i].to])dfs(e[i].to);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        if(x==y)ss++,s[x]++;
        else d[x]++,d[y]++,add();
    }
    cnt=0,ans=1ll*(m-ss)*ss+1ll*ss*(ss-1)/2;
    for(int i=1;i<=n;i++)if(!vis[i]&&d[i]){dfs(i);break;}
    if(cnt!=(m-ss)*2||t!=ss)ans=0;
    printf("%lld\n",ans);
    return 0;
}

T5-The Great Mixing

有k种可乐,第i瓶可乐的CO2浓度是ai/1000,问要配置出浓度n/1000的可乐,最少需要几瓶可乐。

解法

这道题bfs乱搞就可以了,虽然k是1e6,但是判重之后最多1e3,bfs无压力啊
随便设定一个上界,1e6都可以,但1e4就够了,跑完之后如果没有答案就是无解

ac代码

#include<bits/stdc++.h>
using namespace std;
struct node{int v,s;};
queue<node>q;
int n,k,x,cnt,a[1010],vis[1010];
map<int,bool>mp;
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=k;i++){scanf("%d",&x);if(vis[x])continue;vis[x]=1,a[++cnt]=x;}
    for(int i=1;i<=cnt;i++)a[i]-=n,q.push({a[i],1}),mp[a[i]]=1;
    while(!q.empty())
    {
        node u=q.front();
        q.pop();
        if(u.v==0){printf("%d\n",u.s);return 0;}
        for(int i=1;i<=cnt;i++)
        {
            if(mp[u.v+a[i]]||abs(u.v+a[i])>10000)continue;
            mp[u.v+a[i]]=1,q.push({u.v+a[i],u.s+1});
        }
    }
    puts("-1");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值