CF1492
A.Three Swimmers
题目大意:
给出T组数据,每组数据给出p,a,b,c,求最小的是a,b或c的倍数且大于等于p的数与p的差值。
解题思路:
直接做做完了。每次使p分别除以a,b,c(向上取整),取最小值再算差值即可。
小代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
int T;
int a,b,c,p;
signed main()
{
scanf("%lld",&T);
while (T--)
{
scanf("%lld%lld%lld%lld",&p,&a,&b,&c);
int ans=0x3f3f3f3f3f3f3f3f;
ans=min(ans,(p+a-1)/a*a);
ans=min(ans,(p+b-1)/b*b);
ans=min(ans,(p+c-1)/c*c);
printf("%lld\n",ans-p);
}
return 0;
}
B.Card Deck
题目大意:
给出T组数据,每组数据给出栈中的\(n(1\leqslant n\leqslant 1e5)\)个元素\(p_{i}\),每次操作可以取出栈顶若干元素,按原来顺序放入新的栈中,求最后使得新栈值最大的方案。我们定义栈的值为\(\sum_{i=1}^{n} n^{n-i} p_{i}\)(默认栈顶为元素\(p_{n}\),栈底为元素\(p_{1}\))
解题思路:
这题简直就是反过来的出栈序列
容易想到贪心。越大的值越早到新栈里,新栈的值一定会越大。于是乎,我们定义一个前缀最大值数组,从后往前扫描,若出现旧的最大值了就输出当前的栈中所有元素(可结合代码理解)。
小?代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int T;
int n;
int p[N];
stack <int> s;
int mx[N];
signed main()
{
scanf("%lld",&T);
while (T--)
{
scanf("%lld",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&p[i]);
mx[i]=max(mx[i-1],p[i]);//前缀最大值
}
for (int i=n;i>=1;i--)
{
s.push(i);
while (!s.empty()&&mx[s.top()]>mx[i-1])//目前栈中存放的有好用的最大值
{
printf("%lld ",p[s.top()]);
s.pop();
}
}
printf("\n");
}
return 0;
}
C.Maximum width
题目大意:
给出两个长度分别为n,m的字符串\(s1,s2(2\leqslant m\leqslant n\leqslant2e5)\),保证\(s2\)是\(s1\)的一个子串。要求找到\(s1\)的一个与\(s2\)相同的子串,使得该子串中相邻两个字符在\(s1\)中的距离最大,求这个最大值。
解题思路:
想让相邻两个字符距离最大,那么就是让相邻两个字符在可取到的范围里一个取最前面、一个取最后面,这样的距离最大。
于是乎,预处理出\(s2\)中每个字符可取到的最前、最后的位置,最后取最大的\(lst_{i+1}-fst_{i}\)就是答案。
小代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,m;
string s1,s2;
int fst[N],lst[N];
int ans;
signed main()
{
cin>>n>>m>>s1>>s2;
s1=" "+s1,s2=" "+s2;
int j=0;
for (int i=1;i<=m;i++)
{
while (s1[++j]!=s2[i]);
fst[i]=j;
}
j=n+1;
for (int i=m;i>=1;i--)
{
while (s1[--j]!=s2[i]);
lst[i]=j;
}
for (int i=1;i<m;i++) ans=max(ans,lst[i+1]-fst[i]);
cout<<ans;
return 0;
}
D.Genius's Gambit
题目大意:
给出三个整数\(a,b,k(0\leqslant a,1\leqslant b,k\leqslant a+b\leqslant 2e5)\),要求构造出两个二进制形式的整数(x)2,(y)2,使得x,y都由a个"0",b个"1"组成,且\((x-y)_{2}\)有k个"1",输出x,y的构造方案,若无法构造则输出"No"(不允许前导0的存在)
解题思路:
我们不妨构造出最大的x,然后考虑\((x-y)_{2}\)有k个"1"的情况。当x,y相同数位的数不同时,x-y该数位就是1;若此次减法还向上借位,那么一直到上一个\((x)_{2}\)"1"、\((y)_{2}\)"0"的位置借位才会结束,在这个范围内x-y数位上都是1。
于是乎,我们可以在x上进行修改,找到l,r使得\(r-l=k\)并且\(x_{l}=1,x_{r}=0\),将\(x_{l}\)改为0、\(x_{r}\)改为1,这样修改过后的就是我们需要的y了。
挂分小技巧:漏掉无法构造成功的三种情况——a,b,k的边界问题。
不好看的代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int a,b,k;
int a1[N*2],a2[N*2];
int l,r;
signed main()
{
cin>>a>>b>>k;
if ((k+2>a+b&&k!=0)||(b==1&&k!=0)||(a==0&&k!=0))
{
cout<<"No";
return 0;
}
l=2,r=l+k;
for (int i=1;i<=b;i++) a1[i]=a2[i]=1;
for (int i=b+1;i<=a+b;i++) a1[i]=a2[i]=0;
if (k!=0)
{
while (r<=b) l++,r++;
a2[l]=0,a2[r]=1;
}
cout<<"Yes"<<endl;
for (int i=1;i<=a+b;i++) cout<<a1[i];
cout<<endl;
for (int i=1;i<=a+b;i++) cout<<a2[i];
return 0;
}
E.Almost Fault-Tolerant Database
题目大意:
给出n个长度为m的序列a,需构造一个序列s,使得对于任意序列,\(\sum_{i=1}^{m} [a_{i}\neq s_{i}]\leqslant2\)。输出构造方案,若无法构造则输出"No"。(\(nm\leqslant2.5\times10^{5}\))
解题思路(口胡版):
我们不妨令\(s=a_{1}\),跑一遍,记录每个序列与s的最大差值\(\Delta\),若\(\Delta\leqslant2\),那么直接输出s就行;若\(\Delta>4\),那么一定没有构造方案(可感性理解一下)。
那么现在就是\(\Delta=3\)或\(\Delta=4\)的情况了。记差值与\(a_{1}\)最大的序列为\(a_{id}\)
若\(\Delta=3\),考虑\(S=\{ans_{x},ans_{y},ans_{z}\}\),那么\(S\)中必然有一个元素与\(a_{1}\)中的相同,有另一个元素与\(a_{id}\)中的相同(这是显然的)。先令\(ans_{x}=a_{1,x}\),\(ans_{y}=a_{id,y}\),随后再使\(ans_{z}=a_{1,z}\),向上述一样再次跑一遍,若\(a_{id'}\)与\(ans\)有三个不同,那么令\(ans_{z}=a_{id',z}\)再检查第二遍即可。若\(\Delta'>2\),那么枚举下一种方案。共有6种方案,每种方案最多检查2遍,复杂度最多为 \(O(12nm)\)。
若\(\Delta=4\),这是好考虑的,\(S\)中必然有两个元素分别与\(a_{1}、a_{id}\)中的元素相同。共有6种方案,枚举即可,复杂度最多为 \(O(6nm)\)。
口胡完毕