2019杭电多校第九场部分题解(1002,1005,1006)

1002: Rikka with Cake

可以发现,答案=线段之间交点的个数+1。把x坐标离散化,把线段按起点的y坐标排序,先从下往上,求每个down的线段和多少个线段相交。再从上往下,求每个up的线段和多少个线段相交。

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int maxn = 1e5 + 50;
struct node{
    int x, y;
    int op;//0 L, 1 R, 2 U, 3 D
    bool operator < (const node& a){
        return y < a.y;
    }
}e[maxn];
int lz[maxn*4];
int cc[maxn];
int num, n, m, q;
void build(int rt, int l, int r){
    lz[rt] = 0;
    if(l == r) return;
    build(lson); build(rson);
}
void down(int rt){
    lz[rt<<1] += lz[rt];
    lz[rt<<1|1] += lz[rt];
    lz[rt] = 0;
}
void update(int rt, int l, int r, int L, int R){
    if(L <= l && r <= R){
        lz[rt]++; return;
    }
    down(rt);
    if(L <= mid) update(lson, L, R);
    if(R > mid) update(rson, L, R);
}
int qry(int rt, int l, int r, int pos){
    if(l == r){
        return lz[rt];
    }
    down(rt);
    if(pos <= mid) return qry(lson, pos);
    else return qry(rson, pos);
}
void init()
{
    num = 0;
    scanf("%d%d%d", &n, &m, &q);
    cc[++num] = 0; cc[++num] = m;
    for(int i = 0; i < q; ++i){
        char cmd[5];
        scanf("%d%d", &e[i].x, &e[i].y);
        scanf("%s", cmd);
        cc[++num] = e[i].x;
        if(cmd[0] == 'L') e[i].op = 0;
        else if(cmd[0] == 'R') e[i].op = 1;
        else if(cmd[0] == 'U') e[i].op = 2;
        else e[i].op = 3;
    }
    sort(cc+1,cc+1+num);
    num = unique(cc+1,cc+1+num)-cc-1;//x的离散化
}
void sol(){
    sort(e, e+q);//按y从小到大
    ll ans = 1;
    build(1, 1, num);
    for(int i = 0; i < q; ++i){
        if(e[i].op == 0){
            int r = lower_bound(cc+1,cc+1+num, e[i].x) - cc;
            update(1, 1, num, 1, r);
        }
        else if(e[i].op == 1){
            int l = lower_bound(cc+1,cc+1+num, e[i].x) - cc;
            update(1, 1, num, l, num);
        }
        else if(e[i].op == 3){
            int pos = lower_bound(cc+1,cc+1+num, e[i].x) - cc;
            int t = qry(1, 1 , num, pos);
            ans = ans + t;
        }
    }
    build(1, 1, num);
    for(int i = q-1; i >= 0; --i){
        if(e[i].op == 0){
            int r = lower_bound(cc+1,cc+1+num, e[i].x) - cc;
            update(1, 1, num, 1, r);
        }
        else if(e[i].op == 1){
            int l = lower_bound(cc+1,cc+1+num, e[i].x) - cc;
            update(1, 1, num, l, num);
        }
        else if(e[i].op == 2){
            int pos = lower_bound(cc+1,cc+1+num, e[i].x) - cc;
            int t = qry(1, 1 , num, pos);
            ans = ans + t;
        }
    }
    cout<<ans<<endl;
}
int main()
{
    int T;cin>>T;
    while(T--){
        init();sol();
    }
}

1005: Rikka with Game

第一个人如果想让字典序变小,一定会找一个z使得它变成a,同时这个z前面必须全是y。如果不全是y,那么第一个人把z变成a之后,第二个人可以让前面的字母变大,且第一个人无法使之变小。
如果没有满足条件的z,第一个人就不能让字典序更小,直接结束是最优选择。
如果有满足条件的z,第一个人让它变成a之后,第二个人一定会让它变成b,这时第一个人结束游戏是最优选择(否则就算第一个人把后面某个z变成a,第二个人把这个b变成c会让字典序更大)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int maxn = 200;
char s[maxn];
int main()
{
	int T;cin>>T;
	while(T--){
        scanf("%s", s);
        int n = strlen(s);
        int idx = 0;
        while(idx < n && s[idx] >= 'y'){
            if(s[idx] == 'z') break;
            idx++;
        }
        if(s[idx] == 'z') s[idx] = 'b';
        printf("%s\n",s);
	}
}



1006:Rikka with Coin

容易知道,对于答案来说:
1最多有1个(如果需要两个1,那换成一个1,一个2显然更好)
2最多有4个,5最多有1个(与1同理)
那么枚举1,2,5的个数,再看对于每个套餐来说,最少需要多少个10.

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[25];
int w[150];
int n;
int check(int x, int y, int z)//1, 2, 5
{
    memset(dp, 0x3f, sizeof dp);
    dp[0] = 0;
    for(int i = 0; i < x; ++i){
        for(int j = 20; j >= 1; --j){
            dp[j] = min(dp[j], dp[j-1]+1);
        }
    }
    for(int i = 0; i < y; ++i){
        for(int j = 20; j >= 2; --j){
            dp[j] = min(dp[j], dp[j-2] + 1);
        }
    }
    for(int i = 0; i < z; ++i){
        for(int j = 20; j >= 5; --j){
            dp[j] = min(dp[j], dp[j-5]+1);
        }
    }//dp求得1,2,5个数为x,y,z时可以凑的数字
    int res = 0;//需要的额外的10的个数
    for(int i = 0; i < n; ++i){
        int t = w[i]%10;
        int fnd = 0;
        int temp = inf;
        if(dp[t] != inf){
            temp = min(w[i]/10, temp);
            fnd = 1;
        }
        t = t+10;
        if((w[i] >= t) && dp[t] != inf){
            fnd = 1;
            temp = min(temp, (w[i]-t)/10);
        }
        if(!fnd) return -1;
        res = max(res, temp);
    }
    return res;

}
int main()
{
	int T;cin>>T;
	while(T--){
        scanf("%d", &n);
        int ok = 1;
        for(int i = 0; i < n; ++i){
            scanf("%d", &w[i]);
            if(w[i]%10 != 0) ok = 0;
            w[i]/=10;
        }
        if(!ok){
            printf("-1\n"); continue;
        }

        int ans = inf;
        for(int i = 0; i < 2; ++i){//1最多1个
            for(int j = 0; j < 5; ++j){//2最多4个
                for(int k = 0; k < 2; ++k){//5最多1个
                    int u = check(i, j ,k);
                    if(u != -1) ans = min(ans, i+j+k+u);
                }
            }
        }
        printf("%d\n", ans);
	}
}
/*
1
6
1040 1050 1060 1100 150 200
*/
/*
1
6
40 50 60 100 150 200
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值