题库链接:​https://codeforces.com/contest/1413​A. Finding Sasuke
题意:给你一个序列a(长度为n,且n为偶数),让你构造一个序列b,使得Codeforces Round #679 (Div. 2, based on Technocup 2021 Elimination Round 1)_赋值
思路:暴力寻找,每两个为一组
代码:

int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int a[120],b[120];
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i+=2){
int flag=0;
for(int j=-100;j<=100;j++){
for(int k=-100;k<=100;k++){
if(k!=0&&j!=0){
if(j*a[i]+k*a[i+1]==0){
b[i]=j;
b[i+1]=k;
flag=1;
break;
}
}
}
if(flag==1)
break;
}
}
for(int i=1;i<=n;i++){
cout<<b[i]<<" ";
}
cout<<endl;
}
}

B. A New Technique
题意:恢复矩阵,给你矩阵的行,列,顺序是打乱的,保证答案唯一
思路:根据给出的列可以找到代码的第一行,然后根据第一行恢复列的矩阵
第一个矩阵是行变化而列不变的矩阵
第二个矩阵是列变化而行不变的矩阵
故需要先找到原来矩阵中第一行第一列的元素 u[i][1] == v[j][1]
就知道了这个元素的行列,故可以从这个元素出发进行操作对每一列进行赋值,一列一列的赋值
代码:

struct node{
int a[550];
int id;
}str[550];
int b[550][550];

int cmp(node a,node b){
return a.id<b.id;
}

int main(){
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>str[i].a[j];
}
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
cin>>b[i][j];
}
}
int x;int flag=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(b[j][1]==str[i].a[1]){
x=j;flag=1;
break;
}
}
if(flag==1)
break;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(b[x][i]==str[j].a[1]){
str[j].id=i;
break;
}
}
}
sort(str+1,str+1+n,cmp);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<str[i].a[j]<<" ";
}
cout<<endl;
}
}
}

C. Perform Easily
题意:
输入,a1–a6。然后n,接着b1–bn。
问每个b1减去一个a之后的最小的(最大值-最小值)
思路:
我们将所有对(bj−ai,j)按字典顺序排序。现在我们需要找到一个子段,它的最小范围包含第一个字段,并且使从1到n的所有数字都出现在第二个字段中(所以这意味着每个音符至少有一个字符串fret组合)。
对于每个l,表示最小右(l),使[l,right(l)]是有效的子集。很容易看出right(l)≤right(l+1),因为如果[l+1,right(l+1)]包含第二个字段中从1到n的所有数字,那么[l,right(l+1)]也是如此。所以要找到好的(l),你可以使用两个指针,保持在片段上出现的一组音符。
一旦我们计算了它,我们只需打印出所有可能段[l,right(l)]端点的第一个字段之间的最小差异。最后的复杂度是O(nmlog(nm))。
代码:

int a[10],b[maxn];

struct node{
int num;
int id;
}str[maxn*6];

int cmp(node a,node b){
return a.num<b.num;
}
int st[maxn*6];

int cnt=0;

int main(){
for(int i=1;i<=6;i++)
scanf("%d",&a[i]);
int n;
cin>>n;
for(int i=1;i<=n;i++)
scanf("%lld",&b[i]);
for(int i=1;i<=n;i++){
for(int j=1;j<=6;j++){
str[++cnt].id=i;
str[cnt].num=b[i]-a[j];
}
}
sort(str+1,str+1+cnt,cmp);
int r=1,num=0;
int ans=inf;
for(int i=1;i<=cnt;i++){
while(r<=cnt&&num<n){
st[str[r].id]++;
if(st[str[r].id]==1)num++;
r++;
}
if(num==n)ans=min(ans,str[r-1].num-str[i].num);
st[str[i].id]--;if(st[str[i].id]==0)num--;
}
printf("%d\n",ans);
}

D. Shurikens
题意:
一家店卖忍者用的手里剑(应该是手里剑)。每天有n把手里剑,每把剑的价格分别为1~n。店员不是一次性把所有手里剑都摆在柜台上,而是每次摆一把,分n次摆。我们不知道摆剑的顺序。
有忍者来买手里剑,他们每次只买当前摆在柜台上的手里剑中最便宜的一把。
问我们:题目中给出的2n个操作,是不是合理的。如果不合理,输出"NO";如果合理,输出"YES",并另起一行输出一行数列,表示店员放置手里剑的顺序(所有可能中的一种即可)。
关于操作的定义:
"+“表示,店员向柜台放了一把手里剑,至于放的是哪把我们不知道。
“- x"表示有忍者买走了价值为x的手里剑。
关于操作合理的定义:
当柜台为空时,忍者仍买走了一把手里剑,显然是不合理的。
当不能满足所有忍者都购买了当前柜台中最便宜的一把手里剑时,显然也不合理。
思路:
我们可以确定的是,忍者只会买当前柜台中最便宜的一把手里剑。
也就是说当我们遇到”- x"操作时,x必然是当前柜台中最便宜的一把手里剑的价格,即当前柜台中的其他手里剑的价格都比x大。
但是有一个问题,我们根本没有办法确定,当前柜台中价格最低的手里剑是哪一把。因为”+"操作只能告诉我们,店员向柜台中放置了一把手里剑,但是没有告诉我们他放置的手里剑的价格。
那该怎么办呢?有一个想法是,我们根据顾客买的手里剑的价格来确定当前柜台中的手里剑的价格。
所以我们制定一个对我们最有利的规则:忍者买的手里剑总是柜台所有手里剑中最新拿上来的一把。也就是说,最新拿上来的一把就是当前柜台中价格最低的一把。再换句话说,柜员向柜台中摆剑的时候,一定要保证新摆的剑比当前柜台中所有的剑的价格都低!
那有朋友该纳闷了,店员凭啥这么摆啊?咱不是不知道店员摆的顺序吗?
我们之所以这么摆,是因为这样对我们最有利!
正如我们所知道的,我们不知道店员摆手里剑的顺序。我们能做的只能是根据顾客买手里剑的顺序来反推操作是否可行。也就是说,只要对我们最有利的情况是可行的,那这个操作就是可行的。
那我们制定的规则最有利的依据是什么呢?我们在这道题中的限制就是,忍者只会买当前柜台中价格最低的一把手里剑。作为一名奸商 有智慧的商人,我摆的时候顺序一定会是n,n-1,……1.因为你不是总买最便宜的吗,那也就意味着越便宜的手里剑所受的限制就越少,那我当然是先把限制大的给卖出去。
但是我们能不能做到整个过程按照降序摆呢?不能。因为忍者买的时候给出了价格x,也就是说我们要想让操作合理,那就必须保证价格为x的我们已经摆进去了。别等着人家买了个价格为2的,你降序摆才摆到价格为4的。那对于我们来说最优解就是:**先摆贵的,并保证刚好在忍者要买价格为x的手里剑之前,把价值为x的手里剑摆上去。**我刚好在你要买之前把你想要的这个给摆上去。这就是我们的最有利的规则。相信大家也品出味了,刚摆的手里剑是最便宜的,而顾客只买最便宜的。也就是说,越先摆进柜台的就越晚出去。先进后出,这不就是个栈吗!现在写代码就很容易了。
代码

stack<int>v;
int a[maxn];

int main(){
int n;
int cnt1=0,cnt2=0;
cin>>n;
char op[3];
int num=0,x;
for(int i=1;i<=2*n;i++){
cin>>op;
if(op[0]=='+'){
v.push(++num);
}
else{
cin>>x;
if(v.empty()){
puts("NO");
return 0;
}
else if(x<a[v.top()+1]){
puts("NO");
return 0;
}
a[v.top()]=x;
v.pop();
}
}
cout<<"YES"<<endl;
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
}

E. Solo mid Oracle

题意:你有一个技能,每次使用可以使敌方英雄的血量减少a,并在c秒内每秒回复b点生命值,技能的冷却时间为d。问在你能击败的敌方英雄的血量最大为多少。

思路:

Codeforces Round #679 (Div. 2, based on Technocup 2021 Elimination Round 1)_c++_02


代码:

int main(){
int t;
cin>>t;
while(t--){
ll a,b,c,d,ans=0;
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
if(a>b*c){
puts("-1");
}
else{
ll tmp=(c/d);
ll tmp2=(a/(b*d));
tmp=min(tmp,tmp2);
ans=(tmp+1)*a-(tmp*(tmp+1)/2)*b*d;
printf("%lld\n",ans);
}
}
}