A. Stickers and Toys(思维)
原题链接:https://codeforces.com/contest/1187/problem/A
题意:
有n个神秘礼盒, 每个礼盒装着以下三种类型的物品:
- 一个贴纸
- 一个玩具
- 一个贴纸和一个玩具
已知贴纸共t个,玩具共s个,求问至少开几个箱子才能够保证一定至少能获得一个玩具和一个贴纸。
思路: 可以把所有情况都列出来,共有4种情况:
- (s+t)==n
- (s<n&&t<n) && (s+t>n)
- (s==n && t<n) || (s<n && t == n)
- s==n && t ==n
然后会发现,前三种情况的答案都是 n - min(s, t) + 1。第四种特判一下即可。
Code(C++):
#include <iostream>
using namespace std;
int main(){
int k; cin>>k;
while(k--){
int n,s,t;
cin>>n>>s>>t;
if(s==n&&t==n)
cout<<1<<endl;
else
cout<<n-min(s,t)+1<<endl;
}
return 0;
}
B. Letters Shop(思维)
原题链接:https://codeforces.com/contest/1187/problem/B
题意: 给定一个字符串 s,含有 n 个小写字母。m 次询问:给定一个字符串 t,问至少使用 s 的前几个字符可以构造出 t 。字符可以有多余,但必须够用。
思路: 先记录 s[i] 在 s 中的位置 i 出现cnt1次,然后记录询问的字符串中 t[i] 出现 cnt2 次,最后不断更新 t[i] 在 s 中出现的最大位置。
Code(C++):
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=2e5+100;
int sum[30][N],sum1[30],sum2[30];
int main(){
int n; cin>>n;
string s; cin>>s;
for(int i=0;i<n;i++)
sum[s[i]-'a'][++sum1[s[i]-'a']]=i; //s[i]在s中的位置i出现cnt1次
int m; cin>>m;
while(m--){
memset(sum2,0,sizeof(sum2));
string t; cin>>t;
int len=t.size();
int ans=0;
for(int i=0;i<len;i++)
++sum2[t[i]-'a']; //t[i]出现cnt2次
for(int i=0;i<26;i++)
ans=max(ans,sum[i][sum2[i]]); //不断更新t[i]在s中出现的最大位置
cout<<ans+1<<endl;
}
return 0;
}
Code(Java):
import java.util.Scanner;
public class Main {
private static final int N = (int) 2e5+100;
static int[][] sum = new int[30][N];
static int[] sum1 = new int[30];
static int[] sum2 = new int[30];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
String s = cin.next();
for(int i=0;i<n;i++)
sum[s.charAt(i)-'a'][++sum1[s.charAt(i)-'a']]=i;
int m = cin.nextInt();
while(m-- >0) {
for(int i=0;i<30;i++)
sum2[i] = 0;
String t = cin.next();
int len = t.length();
int ans=0;
for(int i=0;i<len;i++)
++sum2[t.charAt(i)-'a'];
for(int i=0;i<26;i++)
ans = Math.max(ans, sum[i][sum2[i]]);
System.out.println(ans+1);
}
}
}
C. Vasya And Array(贪心+构造)
原题链接: https://codeforces.com/contest/1187/problem/C
题意: 给定数组a的长度 n , 有 m 个要求,给出 ti ,li ,ri,要求构造数列:
- ti == 1,在数组区间为 [li, ri] 是非递减的,即上升或相等序列。
- ti == 0,在数组区间为 [li, ri] 不是非递减的,即下降序列。
思路:
- 先把 t==1 的情况处理掉,上升或相等序列,例如序列 3 3 3 3 3,是符合的。把非递减的位置用 b[i] 标记为1,表示a[i] <= a[i-1]。
- 再来处理 t==0 的情况,下降序列,如果存在一个 b[i]!=1 ,即 a[i]>a[i-1],则符合要求。如果一个都不存在,则用vis标记出来,然后输出“NO”后直接结束程序。
- 然后给序列第一个数赋一个足够大的数,至少要大于1000,根据 b[i] 标记,遍历给序列赋值。
- 最后遍历输出序列。
Code1(C++):
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e3+10;
int b[N],ans[N];
struct node{
int t,l,r;
bool operator < (const node &p){ //学习大佬的码风!!!
return t > p.t;
}
}a[N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>a[i].t>>a[i].l>>a[i].r;
sort(a+1,a+1+m);
for(int i=1;i<=m;i++){
if(a[i].t==1){
for(int j=a[i].l+1;j<=a[i].r;j++)
b[j]=1;
}else{
bool vis=false;
for(int j=a[i].l+1;j<=a[i].r;j++){
if(b[j]!=1){
vis=true;
break;
}
}
if(!vis){
cout<<"NO"<<endl;
return 0;
}
}
}
ans[1]=1500;
for(int i=2;i<=n;i++){
if(b[i]==1) //不下降序列,此处是相等序列
ans[i]=ans[i-1];
else //上升序列
ans[i]=ans[i-1]-1;
}
cout<<"YES"<<endl;
for(int i=1;i<=n;i++)
cout<<ans[i]<<" ";
cout<<endl;
return 0;
}