Gym - 101911

题目链接

A. Coffee Break(水题)

题意:

给n个喝咖啡的时刻,每天每两个时刻的间隔不小于d分钟,每天有m分钟,求最少需多少天,输出每个时刻在哪一天,(不考虑周末)

思路:

贪心

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n,m,k;
const int maxn=2e5+10;

struct node{
    int x,y;
    bool operator <(const node &a)const{
        return x<a.x;
    }
}nd[maxn];

bool cmp(node a,node b){
    return a.x>b.x;
}

multiset<node>st;
map<int,int>mp;
multiset<node>::iterator it;

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&nd[i].x);
        nd[i].y=i;
    }
    sort(nd,nd+n,cmp);
    int ans=1;
    for(int i=0;i<n;i++){
        if(st.empty()){
            mp[nd[i].y]=ans++;
            st.insert(nd[i]);
        }
        else{
            it=st.end();
            it--;
            if((*it).x-nd[i].x<=k){
                mp[nd[i].y]=ans++;
                st.insert(nd[i]);
            }
            else{
                it=st.upper_bound(node{nd[i].x+k,0});
                mp[nd[i].y]=mp[(*it).y];
                st.erase(it);
                st.insert(nd[i]);
            }
        }
    }
    printf("%d\n",ans-1);
    for(int i=0;i<n;i++) printf("%d ",mp[i]);
    printf("\n");
    return 0;
}

 

B. Glider (尺取/前缀和)

题意:

给n个区间,区间内高不变,区间外x+1,y就-1,给一个高度h,求h降到0最多能走过多少x

思路:

1.尺取,遍历每个区间时,计算前面降了的h在所求区间末降到0的x,不断修改,每次取最大值(代码写的太丑了,先放上以后在改)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(false);cin.tie(0);

const ll maxn=2e5+10;
ll l[maxn],r[maxn];
int main()
{
    fastio
    ll n,h;
    cin>>n>>h;
    for(ll i=0;i<n;i++) cin>>l[i]>>r[i];
    l[n]=r[n]=1e18;
    ll x=0,y=0,z=h,ans=r[0]-l[0],cnt=0,t=1;
    for(ll i=0;i<n;i++){
        while(t){
            for(ll j=y+1;j<=n;j++){
                if(z<=l[j]-r[j-1]){
                    //ans+=z;
                   // y=r[j-1]+z;
                    //z=0;
                    t=0;
                    break;
                }
                else{
                    ans+=(r[j]-r[j-1]);
                    z-=(l[j]-r[j-1]);
                    y=j;
                }
            }
        }
        t=1;
        cnt=max(cnt,ans+z);
        z+=(l[i+1]-r[i]);
        x=i+1;
        ans-=(l[i+1]-l[i]);
        if(r[y]<l[i+1]){
            y=i+1;
            ans=r[i+1]-l[i+1];
            z=h;
        }
    }
    cout<<cnt<<endl;
	return 0;
}

 

2.前缀和,遍历每个区间,求h降到0的x,取最大值(代码还没写qwq)

 

C. Bacteria(水题)

题意:

给n个数,可以把两个相同的数x合并成一个数x*2,还可以从外界取数来合并,问最后能否合成一个数,若能,输出需要从外界获得多少数,若不能,输出-1;

思路:

排个序,若每个数是他前面的数的2^n倍,则需从外界取得n个数,否则合不成一个数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(false);cin.tie(0);

priority_queue <ll,vector<ll>,greater<ll> > pq;

int main()
{
    fastio
    ll n;
    cin>>n;
    while(n--){
        ll x;
        cin>>x;
        pq.push(x);
    }
    int f=0;
    int ans=0;
    while(pq.size()){
        if(pq.size()==1) break;
        ll x=pq.top();
        pq.pop();
        int f1=0;
        for(int i=0;;i++){
            if((x<<i)>1e18) break;
            if((x<<i)==pq.top()){
                ans+=i;
                pq.pop();
                pq.push(x<<(i+1));
                f1=1;
                break;
            }
        }
        if(!f1){
            f=1;
            break;
        }
    }
    if(f) cout<<-1<<endl;
    else cout<<ans<<endl;
	return 0;
}

D. Masquerade strikes back (水题/注意优化)

题意:

给n个数,每次输出两个数a,b,使得a*b=x,a,b只能出现一次,若行,输出YES,然后是每个a,b,否则,输出NO

思路:

计算每个出现的数的因子,超过出现的次数就break掉,(这里一定要优化!!不然疯狂超时T39,哭唧唧),如果所有因子跑完了还比出现的次数小,就输出NO 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(false);cin.tie(0);

const int maxn=1e7+10;
vector<int>vc[maxn];

int a[maxn],v[maxn],l[maxn];

int main()
{
    memset(a,0,sizeof(a));
    memset(l,0,sizeof(l));
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&v[i]);
        a[v[i]]++;
    }
    for(int i=1;i<=n;i++){
        int x=v[i];
        if(vc[x].size()) continue;
        double ss=sqrt(x);
        for(int j=1;j<=ss;j++){
            if(x%j==0){
                vc[x].push_back(j);
                vc[x].push_back(x/j);
                if(j*j!=x){
                    vc[x].push_back(x/j);
                    vc[x].push_back(j);
                }
            }
            if(a[x]*2<=vc[x].size())//一定要加这个优化!!!!!
                break;//T39T到哭死
        }
        if(a[x]*2>vc[x].size()){//不符合条件
            puts("NO");
           return 0;
        }
    }
    puts("YES");
    for(int i=1;i<=n;i++){
        int x=v[i];
        int y=l[x];
        printf("%d %d\n",vc[x][y],vc[x][y+1]);
        l[x]+=2;
    }
	return 0;
}

 

E   Painting the Fence (线段树+deque)

题意:

染色问题;给n个初始颜色,接下来m个操作,每次操作把最左端的x颜色和最右端的x颜色中间都染成x颜色,输出最后的染色状态

思路:

线段树存颜色,区间颜色相同则值为颜色种类,区间有多种颜色则值为-1;

初始用deque[x]存x颜色的所有存在位置,每次染色时查询deque[x]左端和右端是否为颜色x,若否,删掉此位置往中间位置查找,若是,将此区间染色成x;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn=3e5+10;
deque<int>dq[maxn];
int n,m;
int tree[maxn<<2],vis[maxn<<2];
#define rl (rt<<1)
#define rr (rt<<1|1)
#define imid int mid=(l+r)>>1;

void down(int rt){//将标记往下推,逐层染色
    if(vis[rt]){
        vis[rl]=vis[rr]=vis[rt];
        tree[rl]=tree[rr]=vis[rt];
        vis[rt]=0;
    }
}

void up(int rt){//更新上层的值
    if(tree[rl]==tree[rr]) tree[rt]=tree[rl];
    else tree[rt]=-1;
}

void build(int l,int r,int rt){//普通建树
    if(l==r){
        cin>>tree[rt];
        dq[tree[rt]].push_back(l);
        return;
    }
    imid
    build(l,mid,rl);
    build(mid+1,r,rr);
    up(rt);
}

int ask(int x,int l,int r,int rt){//查询x位置的颜色
    if(l==r && l==x){
        return tree[rt];
    }
    down(rt);
    imid
    if(x<=mid) return ask(x,l,mid,rl);
    else return ask(x,mid+1,r,rr);
}

void update(int x,int y,int z,int l,int r,int rt){//将区间[x,y]染色成颜色z
    if(x<=l && r<=y){
        vis[rt]=tree[rt]=z;
        return;
    }
    down(rt);
    imid
    if(x<=mid) update(x,y,z,l,mid,rl);
    if(y>mid) update(x,y,z,mid+1,r,rr);
    up(rt);
}

int main()
{
    cin>>n;
    memset(tree,0,sizeof(tree));
    memset(vis,0,sizeof(vis));
    build(1,n,1);
    cin>>m;
    while(m--){
        int x;
        cin>>x;
        while(dq[x].size() && ask(dq[x].front(),1,n,1)!=x) dq[x].pop_front();
//找最左端的颜色x的位置
        while(dq[x].size() && ask(dq[x].back(),1,n,1)!=x) dq[x].pop_back();
//找最右端的颜色x的位置
        if(dq[x].size()) update(dq[x].front(),dq[x].back(),x,1,n,1);
//将x包括的区间染色
    }
    for(int i=1;i<=n;i++) cout<<ask(i,1,n,1)<<' ';
    cout<<endl;
    return 0;
}

F. Tickets

题意:

每个数的幸运值是他的前三位数字之和与后三位数字之和的差的绝对值,求比x小的数中幸运值大于x的幸运值的数的个数,

思路:

打表

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn=1e6+100;
int a[maxn];
int dp[30];

void init(){
    memset(a,0,sizeof(a));
    memset(dp,0,sizeof(dp));
    for(int i=0;i<maxn;i++){
        int z=i,x=0,y=0;
        for(int j=0;j<3;j++){
            x+=z%10;
            z/=10;
        }
        for(int j=0;j<3;j++){
            y+=z%10;
            z/=10;
        }
        int ans=abs(x-y);
        a[i]=dp[ans];
        for(int j=ans+1;j<30;j++) dp[j]++;
    }
}

int main()
{
    init();
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        cout<<a[x]<<endl;
    }
	return 0;
}

 

G. Tree Reconstruction(思维)

题意:

有一个n个点的树,每擦掉一条线,输出两边的最大值,问这个树是否存在

思路:

不管怎么擦,某一边的最大值一定是n,按另一边的最大值m给树赋值,保证此时的最大值为m,若m出现过,且找不到小于m的数,则这棵树不存在

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int a[1010];

int main()
{
    int n;
    cin>>n;
    set<int>st;
    for(int i=1;i<=n;i++) st.insert(i);
    int x;
    int f=0;
    for(int i=1;i<n;i++){
        cin>>a[i]>>x;
        if(x!=n) f=1;//一边的最大值一定是n
    }
    sort(a+1,a+n);
    vector<int>vc;
    for(int i=1;i<n;i++){
        if(st.count(a[i])){//保证此时的最大值是a[i]
            vc.push_back(a[i]);
            st.erase(a[i]);
        }
        else{
            if(*st.begin()>a[i]){//若此时有更大的数,则最大值不为a[i],这棵树不存在
                f=1;
                break;
            }
            vc.push_back(*st.begin());
            st.erase(st.begin());
        }
    }
    if(f){
        cout<<"NO"<<endl;
        return 0;
    }
    cout<<"YES"<<endl;
    vc.push_back(n);
    for(int i=0;i+1<vc.size();i++)   cout<<vc[i]<<' '<<vc[i+1]<<endl;
    return 0;
}

H. Theater Square(水题)

题意:

给一个nXm的广场,广场中有一个左上角为(x1,y1),右下角为(x2,y2)的喷泉,给给广场铺1X2的瓷砖,只能水平铺,可以将1X2的瓷砖破成1X1的瓷砖,问最少需要破多少瓷砖

思路:

瞎搞瞎搞

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(false);cin.tie(0);

int main()
{
    int n,m;
    cin>>n>>m;
    int x1,y1,x2,y2;
    cin>>x1>>y1>>x2>>y2;
    int ans=0;
    if(m%2==1) ans+=(n-(x2-x1+1));
    if((y1-1)%2==1) ans+=(x2-x1+1);
    if((m-y2)%2==1) ans+=(x2-x1+1);
    cout<<(ans+1)/2<<endl;
	return 0;
}

I. Heist(水题)

题意:

商店里的物品都是连号的,给出丢失了一些物品之后的号,问最少丢了多少物品

思路:

瞎搞瞎搞,计算最大值最小值当成原来的最大值和最小值,然后减去还在的号就是丢了的

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(false);cin.tie(0);

int main()
{
    int n;
    cin>>n;
    int x=1e9+10,y=0;
    for(int i=0;i<n;i++){
        int t;
        cin>>t;
        x=min(x,t);
        y=max(y,t);
    }
    cout<<y-x+1-n<<endl;
	return 0;
}

J. Buying a TV Set(水题)

题意:

求w<a,h<b,w/h=x/y,满足条件的w,h有多少种

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(false);cin.tie(0);

ll gcd(ll x,ll y){
    return x?gcd(y%x,x):y;
}

int main()
{
    ll x,y,a,b;
    cin>>x>>y>>a>>b;
    ll c=gcd(a,b);
    a/=c,b/=c;
    cout<<min(x/a,y/b)<<endl;
	return 0;
}

K. Medians and Partition(规律题)

题意:

给一段序列,求多少子序列的中位数不小于k

思路:

强行找规律,

每次一个小于k的值,至少需要2个不小于k的数,2个小于k的数,至少需要3个,,,,x个,需要x+1个,

不小于k的值一个就是一个序列,而且举例发现跟位置没有关系,

所以用数列中不小于k的数量减去小于k的数量,若为负输出0,

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(false);cin.tie(0);

int main()
{
    int n,k;
    cin>>n>>k;
    int x=0,y=0;
    while(n--){
        int m;
        cin>>m;
        if(m<k) x++;
        else y++;
    }
    cout<<(y-x<0?0:y-x)<<endl;
	return 0;
}

L不会qwq告辞

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值