写在前面
笔者目前处于大二寒假期间,参加牛客寒假训练赛,水平应该在参与该训练赛成员的中上等,每一场比赛都会把我能补但是赛时没出的题补掉,今天是第一场训练赛
这场我决定补两个题,分别是思维、贪心
本篇博客题面和题解皆来自牛客训练赛:ac.nowcoder.com/acm/contest…
B
题面:
赛时没开出来的原因是误解题意,读题的时候其实注意到了,一张牌如果没有用的话,会保留下来,但是思考的时候误认为一张牌只能用一次,然后越想越复杂,最后没做出来
正解:
将a数组的数字从大到小排序,如果b数组有比a数组的数字更小的牌,那么无论这张牌放在哪里,比它大的牌一定可以获取一分(因为小牌出不去会一直保留)。
因为a一张牌最多获得一分,且这一分是谁给的不重要,所以只要关注b数组牌面最小的一张牌即可。换句话说,如果a数组的牌大于b数组牌面最小的一张牌,那么这张牌一定可以获取分数。
因此需要统计a数组中大于minb的数量和小于minb的数量,记为numd和numx。
现在只剩一个限制了,那就是minb不能被消除,即小于minb的牌绝对不能在没有让minb完全发挥作用前和minb配对。所以需要将大于minb的数放在小于minb的数之前
而这两部分内部可以随意排列,最后的结果就是两部分内部排列种数的乘积
注意在过程中要取模
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=998244353;
void solve()
{
ll n;
cin>>n;
vector<ll>a(n);
vector<ll>b(n);
for(auto &t:a) cin>>t;
for(auto &t:b) cin>>t;
auto temp=min_element(b.begin(),b.end());
ll minb=*temp;
ll numd=0,numx=0;
for(auto t:a)
{
if(t>minb) numd++;
else numx++;
}
ll ans=1;
for(int i=1;i<=numd;i++)
{
ans=(ans*i)%MOD;
}
for(int i=1;i<=numx;i++)
{
ans=(ans*i)%MOD;
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
G
题面:
这个题本质上是很简单的,但是赛时思考过于混乱,将很多同种情况分成不同情况考虑,最终乱得实在写不出来了
先附上笔者赛时复杂思路:
先比较l和r的位数
若l位数小于r,则只需要关注r
把每一位提取出来
若全部是9直接毕业
若首位不是1,且后边有不是9的数,将首位-1,其余位置全变成9
若首位是1,且后边有不是9的数,则从前往后找到第一个不是0的数,将其-1.这一位后的所有数变成9
若后边没有不是9的数,直接翻转就行
若l位数和r相等,则从前往后依次比较每一位大小,直到找到r比l大的那一位,然后前边的不动,这一位扣1,后边变9
若找到的这一位后边的已经全是9了,就不需要操作直接反转,如果直到最后一位才找到,也直接反转
若最终操作后有前导0,则去除前导零
这个思路最后通过 30%的样例
其实这个思路大概方向是对的,但是太混太乱了,而且没有这么复杂,很多情况应该归为一类情况
正解:
明显的,想要使折叠数最大,那么要针对R修改:从后往前,一定要保证9最多且位数最长
根据配9的难易程度可以分为两种情况:
一是配9不需要掉位,一是配9需要掉位
配9需要掉位的只有一种情况:100000000……0000,这种情况下折叠数是1,所以必须掉位变成99999……9999,此时若L!=R,与L是几无关,若L=R,那么直接输出1就行
剩余的都是不需要掉位的情况。那么L位数如果小于R,这个界限将毫无用处,所以需要将L视作与R位数相同的10000……0000,如果L位数等于R,那么正常进行下一步即可
现在需要将L和R从高位到低位遍历,如果R这一位高于L,那么可以将这一位扣1,后续全部变成9,这样结果必然是最优的,不过需要注意的是,若这一位后的已经全部是9,这一位可以直接保留
将最终得到的数反转就是答案
有一个很关键的地方是要去除前导零
代码 :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
ll l,r;
cin>>l>>r;
string L=to_string(l);
string R=to_string(r);
ll numl=L.size();
ll numr=R.size();
if(R[0]=='1')
{
bool tiqian=true;
for(int i=1;i<R.size();i++)
{
if(R[i]!='0') tiqian=false;
}
if(tiqian==true&&numl<numr)
{
cout<<r-1<<endl;
return;
}
if(tiqian==true&&numl==numr)
{
cout<<1<<endl;
return;
}
}
if(numl<numr)
{
L.clear();
L.push_back('1');
for(int i=0;i<numr-2;i++) L.push_back('0');
L.push_back('1');
}
for(int i=0;i<numr;i++)
{
if(R[i]!=L[i])
{
bool tiqian=true;
for(int j=i+1;j<numr;j++)
{
if(R[j]!='9') tiqian=false;
}
if(tiqian==true)
{
reverse(R.begin(),R.end());
cout<<R<<endl;
return;
}
else
{
for(int j=i+1;j<numr;j++)
{
R[j]='9';
}
R[i]--;
reverse(R.begin(),R.end());
cout<<R<<endl;
return;
}
}
}
reverse(R.begin(),R.end());
for(int i=0;i<R.size();i++)
{
if(R[i]!='0')
{
for(int j=i;j<numr;j++) cout<<R[j];
cout<<endl;
return;
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
篇末总结
这两道题,我都是具备赛时开出来的能力的,一方面是太长时间没写题了,一方面是能力仍有欠缺,思考不够全面不够宏观,还有就是题意理解错误
这场最后我的成绩是六道,最后大概是1500名左右,我已经相对满意了