gym 101911

A. Coffee Break

题意:每天有m小时,你喝咖啡需要花一小时,你想在n个时刻都喝过一次咖啡,老板规定连续喝咖啡的间隔必须是d以上,求最少需要多少天才能喝够n次咖啡,并输出每个时刻第几天喝。

 

题解:map+优先队列,用map将愿意喝咖啡的时间喝在第几天喝咖啡映射起来,优先队列遍历每个时刻和上一次喝的时间间隔是否大于d,若大于d,表示可以同一天喝,否则就在下一天喝

 

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string>
#include<string.h>
#include<vector>
#include<utility>
#include<map>
#include<queue>
using namespace std;
map<int,int>m;
priority_queue<int,vector<int>,greater<int> >p;
int a[200005],b[200005];
int main()
{
    int n,t,d;
    scanf("%d%d%d",&n,&t,&d);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&b[i]);
        a[i]=b[i];
    }
    sort(a,a+n);
    m[a[0]]=1;//最小的时间点一定是第一天就可以喝
    p.push(a[0]);
    int cnt=1;
    for(int i=1;i<n;i++)
    {
        int now=p.top();
        if(a[i]-now>d)
        {
            m[a[i]]=m[now];//可以同一天喝
            p.pop();
        }
        else
            m[a[i]]=++cnt;//只能下一天喝
        p.push(a[i]);
    }
    printf("%d\n",cnt);
    for(int i=0;i<n;i++)
    {
        if(i==0)
            printf("%d",m[b[i]]);
        else
            printf(" %d",m[b[i]]);
    }
    printf("\n");
    return 0;
}

 

B

题意:有nn个上升气流带,在这里飞行不会下降,否则每前进一会下降1格。求出从某个起点能飞的尽可能远的距离。

题解:起点肯定是某个区间的起点,但枚举起点显然会超时,但显然从当前起点向前可以穿过的区间数和其花费是单调递增,所以处理出前缀和后枚举起点二分终点即可获得答案

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string>
#include<string.h>
#include<vector>
#include<utility>
#include<map>
#include<queue>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;
ll start[200005],sum[200005],len[200005],len2[200005];
int main()
{
    ll n,h;
    scanf("%lld%lld",&n,&h);
    for(int i=1;i<=n;i++)
    {
        ll l,r;
        scanf("%lld%lld",&l,&r);
        start[i]=l;
        len[i]=r-l;//区间长度
    }
    for(int i=1;i<=n-1;i++)
        len2[i]=start[i+1]-(start[i]+len[i]);//两个区间之间的间隔长度

    len2[n]=mx;
    for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+len2[i];//前缀和
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        ll l=i,r=n,mid,pos;
        while(l<=r)
        {
            mid=l+(r-l)/2;
            if(sum[mid]-sum[i-1]>=h)
            {
                pos=mid;
                r=mid-1;
            }
            else
                l=mid+1;
        }
        ll hh=h-(sum[pos-1]-sum[i-1]);//最后一段飘的距离
        ans=max(ans,start[pos]-start[i]+len[pos]+hh);
    }
    printf("%lld\n",ans);
    return 0;

}

 

 

 

 

C. Bacteria

题意:碗里有n个细菌,只有重量相同的细菌才可以合并在一起,合并后的细菌为两个细菌之后,为了把碗里的所有细菌合并成一个细菌,问最少还要向碗里增加几个细菌?若最后不能合并成一个细菌,输出-1,否则输出最少要加入的细菌个数

 

题解:优先队列逐个处理即可

#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;
ll gcd(ll a, ll b)//最大公约数
{
    return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b)//最小公倍数
{
    return a / gcd(a, b) * b;
}
priority_queue<ll,vector<ll>,greater<ll> > p;
int main()
{
    ll n;
    scanf("%lld",&n);
    for(int i=0;i<n;i++)
    {
        ll temp;
        scanf("%lld",&temp);
        p.push(temp);
    }
    ll flag=0,cnt=0;
    while(p.size()!=1)
    {
        ll now=p.top();
        p.pop();
        if(p.size()==1)
        {
            if(lcm(now,p.top())!=p.top())
            {
                flag=1;
                break;
            }
        }
        if(now==p.top())
        {
            now=now+p.top();
            p.pop();
            p.push(now);
        }
        else
        {
            cnt++;
            now=now*2;
            p.push(now);
        }
    }
    if(flag==1)
        printf("-1\n");
    else
        printf("%lld\n",cnt);
    return 0;
}

 

 

D、

题意:给你nn个数,你要给出不同的组合(a,b)(a,b)使得ab=A[i]ab=A[i],不能重复,但是(a,b)(a,b)和(b,a)(b,a)不同

 

题解:按照输入顺序枚举每一个数的因子,枚举到一个因子num[i]之后就退出,同时用vis[]反向标记一下这个数,下一次再次遇到这个数,就从上一次的因子num[i]+1继续枚举

用pair数组保存每一个数的一对因子

 

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string>
#include<string.h>
#include<vector>
#include<utility>
#include<map>
using namespace std;
int vis[10000005],num[10000005];//vis反向标记,用num保存一个因子
pair<int,int>p[200005];
int a[200005];
int n;
int solve()
{
    for(int i=0;i<n;i++)
    {
        if(vis[a[i]]==1)
        {
            vis[a[i]]=0;
            p[i].first=a[i]/num[a[i]];
            p[i].second=num[a[i]];
            continue;
        }
        int flag=0;
        for(int j=num[a[i]]+1;j<=sqrt(a[i]);j++)//对于每个数从最小的因子开始找,找到一对就退出,下一次再次遇到这个数就从num[a[i]]+1开始找因子
        {
            if(a[i]%j==0)
            {
                flag=1;
                num[a[i]]=j;//num只存一个因子即可
                if(a[i]/j!=j)
                    vis[a[i]]=1;//反向标记,例如第一次找到一组[1,3],用vis标记[3,1]的存在
                p[i].first=j;
                p[i].second=a[i]/j;
                break;//对于每个数,找到一对因子就退出
            }
        }
        if(flag==0)
            return 0;
    }

    return 1;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        num[a[i]]=0;//初始化a[i]的因子为0
    }
    if(solve())
    {
        printf("YES\n");
        for(int i=0;i<n;i++)
            printf("%d %d\n",p[i].first,p[i].second );
    }
    else
        printf("NO\n");
}

 

E

题意:有n块木板初始有颜色ai...an,刷m次漆,每次刷漆选择一种颜色从当前颜色的最左端刷到当前颜色的最右端,问经过m次刷漆以后最终木板的颜色序列

思路:用set维护各颜色拥有的木板下标,每次涂色直接取set.begin和set.rbegin进行刷漆,此外当一种颜色刷过以后,它所刷过的区间就不再需要遍历,将其左右边界流在set里即可,下次再遍历到这些点直接跳过该区间

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string>
#include<string.h>
#include<vector>
#include<utility>
#include<map>
#include<queue>
#include<set>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;
int a[300005],vis[300005];
set<int>p[300005];
int main()
{
    int n,m,x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        p[a[i]].insert(i);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&x);
        if(p[x].size()<2||vis[x])
        {
            vis[x]=1;
            continue;
        }
        int l=*(p[x].begin());//*注意优先级
        int r=*(p[x].rbegin());
        for(int j=l+1;j<=r-1;j++)//保留第一个和最后一个位置,中间的位置全部删除
        {       
            p[a[j]].erase(j);
            if(vis[a[j]]==1&&p[a[j]].size()>=1)//遍历过的值直接跳到相应位置开始删除位置
            {
                j=*(p[a[j]].begin());
                p[a[j]].erase(j);
            }
        }
        vis[x]=1;
    }   
    for(int i=0;i<300005;i++)
    {
        if(vis[i]==1&&p[i].size()>=2)//填充中间位置的数
        {
            int l=*(p[i].begin());
            int r=*(p[i].rbegin());
            for(int j=l;j<=r;j++)
                a[j]=i;
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(i==1)
            printf("%d",a[i]);
        else
            printf(" %d",a[i]);
    }
    printf("\n");
    return 0;
}

 

 

 

F. Tickets

题意:有n次询问每次询问给一个数x,且x自动补全六位ABCDEF(可以有前导零),一个数的不幸运值=abs((D+E+F)-(A+B+C)),求出每个在这个数之前比自己不幸运值低的数的个数

 

题解:提前预处理所有数的不幸运值,然后统计比这个不幸运值低的数的个数

#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<map>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;
int a[1000005],cnt[300];
ll gcd(ll a, ll b)//最大公约数
{
    return b == 0 ? a : gcd(b, a % b);
}
int num(int i)
{
    int x=0, y=0;
    int xx=0,yy=0;
    x=i%1000;
    y=i/1000;
    while(x)
    {
        int temp=x;
        x=x/10;
        xx=xx+temp%10;
    }
    while(y)
    {
        int temp=y;
        y=y/10;
        yy=yy+temp%10;
    }
    return abs(xx-yy);
}

int main()
{
    int x;
    memset(cnt, 0, sizeof(cnt));
    for(int i=0; i<1000000; i++)
    {
        a[i] = 0;
        x = num(i);
        cnt[x]++;
        for(int j=0; j<x; j++)
        {
            a[i]+=cnt[j];
        }
    }
    int n;
    scanf("%d", &n);
    while(n--)
    {
        scanf("%d", &x);
        printf("%d\n", a[x]);
    }
    return 0;
}

 

H. Theater Square

题意:有一个矩形,挖掉一个小矩形之后用1*2的方块填充这个矩形,填充不完整的地方(会留有一些1*1)需要将1*2的方块打碎成两块用来填充,问打碎多少块1*2的方块

 

模拟即可

#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<map>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;
int a[1000005],cnt[300];
ll gcd(ll a, ll b)//最大公约数
{
    return b == 0 ? a : gcd(b, a % b);
}
int num(int i)
{
    int x=0, y=0;
    int xx=0,yy=0;
    x=i%1000;
    y=i/1000;
    while(x)
    {
        int temp=x;
        x=x/10;
        xx=xx+temp%10;
    }
    while(y)
    {
        int temp=y;
        y=y/10;
        yy=yy+temp%10;
    }
    return abs(xx-yy);
}

int main()
{
    int x;
    memset(cnt, 0, sizeof(cnt));
    for(int i=0; i<1000000; i++)
    {
        a[i] = 0;
        x = num(i);
        cnt[x]++;
        for(int j=0; j<x; j++)
        {
            a[i]+=cnt[j];
        }
    }
    int n;
    scanf("%d", &n);
    while(n--)
    {
        scanf("%d", &x);
        printf("%d\n", a[x]);
    }
    return 0;
}

 

I

题意:对一组本来连续的数,现在缺失了几个,问你最少缺失了几个

#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;
ll a[1005];
int main()
{
   ll n;
   scanf("%lld",&n);
   for(int i=0;i<n;i++)
    scanf("%lld",&a[i]);
    sort(a,a+n);
    int cnt=0;
    for(int i=1;i<n;i++)
        cnt=cnt+a[i]-a[i-1]-1;
    printf("%d\n",cnt);
}

 

J

题意:多少组w、h的比例满足x/y,要求w<=a&&h<=b

题解:将x/y化成最简分数,答案就是min(a/x,b/y);

#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;

ll gcd(ll a, ll b)//最大公约数
{
    return b == 0 ? a : gcd(b, a % b);
}
int main()
{
   ll a,b,x,y,xx;
   scanf("%lld%lld%lld%lld",&a,&b,&x,&y);
   xx=gcd(x,y);
   x=x/xx;
   y=y/xx;
   printf("%lld\n",min(a/x,b/y));
}

 

K

题意:可以将n个数进行区间分割要求每个区间的中位数>=m问最多可以分成多少个区间

题解:先将所有数从小到大排序,找到第一个满足条件的中位数,之后的所有数都满足条件

#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#define mx 0x3f3f3f3f
#define ll long long
using namespace std;
ll gcd(ll a, ll b)//最大公约数
{
    return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b)//最小公倍数
{
    return a / gcd(a, b) * b;
}
priority_queue<ll,vector<ll>,greater<ll> > p;
int a[5005];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    sort(a,a+n);
    int len=0,now=0,cnt=0;
    for(int i=0;i<n;i++)
    {
        if(a[i]>=m)
            break;
        len++;
    }

    for(int i=len;i<n;i++)
    {
        if(a[i]>=m&&len==now)
        {
            cnt++;
            cnt=cnt+n-(i+1);
            break;
        }
        else
            now++;
    }
    printf("%d\n",cnt);
    return 0;
}

 

posted @ 2019-08-11 22:19  知道了呀~  阅读(321)  评论(0编辑  收藏  举报