2022暑期个人训练赛第03场解题体会

问题 B: double u

题目描述

手写体的"uu"和"w","nn"和"m"简直让人难以辨认。

某人拿到了一个手写体字符串s,她只能按照这个字符串某种可能的形式将其记录下来。具体来说,对于字符串内的一个子串"uu",她有可能记录成"w",对于子串"w",可能记录成"uu"。同样对于子串"nn",可能记录成"m",对于子串"m",可能记录成"nn"。而对于u,w,n,m以外的其它字符,则不会出现记录错误。
更糟糕的是,她记录完后,下一个人按照她的记录进行再一次记录时又会产生同样的错误。

现在拿到牛妹拿到了不知道被反复记录了多少次的字符串t,万幸的是她知道了这个字符串原本的长度为n,即∣s∣=n。她现在希望你帮她恢复出这个字符串s,如果有多种可能性,任意一种符合题意的s都会被认为是正确的。

输入

第一行一个整数T,表示数据组数。
接下来每两行代表一组数据。对于每一组数据,
其第一行,一个正整数n,表示原串s的长度;
其第二行,一个字符串t,表示s经过反复记录后的字符串。保证t串仅由小写字母组成。

输出

输出T行,第i行对应第i组数据的原串s。如果有多种可能性,任意一种符合题意的s都会被认为是正确的。数据保证存在至少一个答案。

思路:

若n>s.size(),则将 ‘m’和‘w’裂解相应个数即可;若n<s.size(),一开始我只考虑‘uu’或‘uwu’这两种情况,只过了90%,对于类似与两个u无法直接相连的子串 “uwwwu” 会漏;把其看作一连串的‘u’处理即可。

AC代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        string s;
        cin>>n>>s;
        if(n>s.size())
            {   int k=n-s.size();
                for(int i=0;i<s.size();i++)
                {
                    if(s[i]=='m'&&k) {cout<<"nn";k--;}
                    else if(s[i]=='w'&&k) {cout<<"uu";k--;}
                    else cout<<s[i];
                }
            }
        if(n<s.size())
        {
            int k=s.size()-n;
            for(int i=0;i<s.size();i++)
            {
                if(s[i]=='u'&&s[i+1]=='u'&&k) {cout<<"w";k--;i++;}
                else if(s[i]=='n'&&s[i+1]=='n'&&k) {cout<<"m";k--;i++;}
                else if(s[i]=='u'&&s[i+1]=='w'&&k) {cout<<"w";s[i+1]='u';}
                else if(s[i]=='n'&&s[i+1]=='m'&&k) {cout<<"m";s[i+1]='n';}
                else cout<<s[i];
            }
        }
        if(n==s.size()) cout<<s;
        cout<<endl;
    }
    return 0;
}

问题 E: 饼干 (biscuit)

您有n台烤箱,第i台烤箱每分钟最多可以烤制vi块饼干。
但是由于质量问题,第i台烤箱最多只能烤mi块饼干
由于家长快要回来了,你只有t分钟时间烤制饼干。
同样由于插头数只有k个,因此您只能用k台烤箱。
特别注意的是一个烤箱一旦插入插头就不能拔出。也就是说一个插头必须对应一个烤箱,不能在达到第一个烤箱容量上限后拔掉插入另一个烤箱。
您希望知道您能不能烤完所有的饼干。如果可以,您还希望知道完成的最早时间;如果不行,您希望知道最多能烤多少块饼干。

输入

输入将严格遵循以下格式:
L n t k
v1 m1
v2 m2
...
vn mn
第一行四个正整数L,n,t,k(1≤L≤109,1≤n≤105,1≤t≤109,1≤k≤n),分别表示需要烤制的饼干数、烤箱数量、限制时间和最多能使用的烤箱数量。
接下来n行,每行两个整数vi,mi(1≤vi≤mi≤L),表示第i台烤箱每分钟最多烤制的饼干数和最多烤制饼干数。

输出

第一行输出一个字符串。若可以烤完,输出 Yes;若不能烤完,输出 No。
第二行输出一个正整数。若可以烤完,输出最早烤完的时间;若不能烤完,输出最多能烤完的饼干数。

这题我改了很多次最后还是只过95的样例写下自己的思路以后再看看

思路:

按照在t分钟可做饼干数降序排列,求前k项和cnt与l比较,若cnt<l则无法完成;若从cnt>=l,则二分答案找最短时间。

95分代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int l,n,t,k;
ll key=99999999999;
struct lx
{
    ll v,m,m1;
}a[N];
bool cmp(lx a,lx b)
{
    return a.m1>b.m1;
}
bool check(int mid)
{
    for(int i=1;i<=n;i++) a[i].m1=min(mid*a[i].v,a[i].m);
    if(mid>=key);   //key表示不会超过m限制的最大时间
    sort(a+1,a+n+1,cmp);
    ll cnt=0;
    for(int i=1;i<=k;i++) cnt+=a[i].m1;
    if(cnt>=l) return true;
    return false;
}
int main()
{
    //ios::sync_with_stdio(false);
    ll cnt=0;
    scanf("%d%d%d%d",&l,&n,&t,&k);
    //cin>>l>>n>>t>>k;
    for(int i=1;i<=n;i++) {
       scanf("%lld%lld",&a[i].v,&a[i].m);
       //cin>>a[i].v>>a[i].m;
        a[i].m1=min(a[i].m,t*a[i].v);
        key=min(key,a[i].m/a[i].v);
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=k;i++) cnt+=a[i].m1;
    if(cnt<l) printf("No\n%lld",cnt);//cout<<"No\n"<<cnt;
    else
    {
        //cout<<"Yes\n";
        printf("Yes\n");
        int l=-1,r=t+1;
        while(l+1<r)
        {
            int mid=(l+r)/2;
            if(check(mid)) r=mid;
            else l=mid;
        }
        printf("%d",r);
        //cout<<r;
    }
    return 0;
}

问题 K: Range Count Query

题目描述

You are given a sequence of length N: A=(A1,...,AN).Answer Q queries given in the following format.
You are given integers L, R, and X.
Find the number of elements among AL, ..., AR whose values are equal to X.
Constraints
1 ≤ N ≤ 2× 105
1 ≤ Ai ≤ N
1 ≤ Q ≤ 2× 105
1≤L ≤ R ≤ N, 1 ≤ X ≤ N, for each query.
All values in input are integers.

输入

Input is given from Standard Input in the following format:
N
A1 A2 ... AN
Q
Query1
Query2
.
.
.
QueryQ

输出

Print Q lines, the i-th of which contains the answer to the i-th query.

题目大意:

有个长度为n的序列,有q个查询 l,r,x 问区间 [l , r]有多少个x

思路:

我只想到存下每个数的出现的位置,还用的是链式前项星(我还是太菜了),循环判断是否在区间l-r内,超时了83。看了下大佬的题解 用vector存下位置,在二分查找l,r在vector的位置,用到了lower_bound()和upper_bound()函数,输出位置差即可.复杂度O(qlogn)

大佬代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N = 2e5 + 10;
int a[N];
vector<int> idx[N];

int main() {
    int n;
    cin >> n;
    for (int i = 1;i <= n;i ++ ) {
        cin >> a[i];
        idx[a[i]].push_back(i);
    }
    int q;
    cin >> q;
    while (q -- ) {
        int l,r,x;
        cin >> l >> r >> x;

        int lidx = lower_bound(idx[x].begin(),idx[x].end(),l) - idx[x].begin();
        int ridx = upper_bound(idx[x].begin(),idx[x].end(),r) - idx[x].begin();
        cout << ridx - lidx << '\n';
    }

    return 0;
}

lower_bound用于查找容器中大于等于某值的数,返回这个数的指针。
upper_bound用于查找容器中大于某值的数,返回这个数的指针。

​​lower_bound(vector.begin(),vector.end(),x)-vector.begin()

问题 J: Dice Sum

题目描述

How many integer sequences of length N, A=(A1, ..., AN), satisfy all of the conditions below?
1≤Ai≤M (1≤ i ≤N)

Since the count can get enormous, find it modulo 998244353.
Constraints
1 ≤ N, M ≤ 50
N ≤ K ≤ NM
All values in input are integers.

有时间再补

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值