题目链接:http://codeforces.com/contest/1187/problem
Problem A
我们要先想出最糟糕的情况是取完 只有1 和 只有2 中较大的,才取到另一种
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<map>
#define ll long long
#define debug(x) printf("----Line%s----\n",#x)
using namespace std;
const int N = 1e5+5;
int main()
{
int T;scanf("%d",&T);while (T--){
//int n;while (~scanf("%d",&n)){}
ll n,s,t;
scanf("%I64d %I64d %I64d",&n,&s,&t);
ll gg = (s+t-n);
ll ans = max(s-gg,t-gg)+1;
printf("%I64d\n",ans);
}
return 0;
}
Problem B
记录主串每个字母第几次出现的位置
每次询问统计询问串所有出现的字母的个数,在主串中找,取最大的
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<unordered_map>
#include<map>
#include<vector>
#define ll long long
#define debug(x) printf("----Line%s----\n",#x)
#define pb push_back
using namespace std;
const int N = 2e5+5;
char s[N];
vector<int>ve[30];///ve[i][j]代表字符i对应的
#define idx(i) i-96
int cnt[30];
int main()
{
//int T;scanf("%d",&T);while (T--){}
int n;while (~scanf("%d",&n)){
for (int i=1;i<=26;i++) ve[i].clear();
scanf("%s",s);
for (int i=0;s[i];i++)
ve[idx(s[i])].pb(i+1);
int q;
scanf("%d",&q);
while (q--){
memset(cnt,0,sizeof cnt);
scanf("%s",s);
for (int i=0;s[i];i++)
cnt[idx(s[i])]++;
int ans = 0;
for (int i=1;i<=26;i++)
if (cnt[i]) ans = max(ans,ve[i][cnt[i]-1]);
printf("%d\n",ans);
}
}
return 0;
}
Problem C
线段树维护递增的线段,是线段,不是区间内的数!
其他东西都在代码中
注释第三行的意思是初始:n,n-1,.......,3,2,1
//Educational Codeforces Round 67 (Rated for Div. 2)
//http://codeforces.com/contest/1187/problem/C
///贪心的思想:尽可能制造处理必须递增的递增,其他都递减的情况,所以初始情况为递减
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid int m = l+r>>1
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]
using namespace std;
const int N = 1e3+5;
int tree[N<<2];///维护递增的线段
bool increase[N];///increase[i] = true 表示区间[i,i+1]递增 ,increase[i] = false 表示区间(i,i+1]递减,但是只有一段区间的话只有一个数,因为下段递增,所以重新排列
int op[N],l[N],r[N];
void push_up(int rt)
{
tree[rt] = tl+tr;
}
void push_down(int rt,int len)
{
tl = len-len/2;
tr = len/2;
}
void update(int L,int R,int rt,int l,int r)///记得R-1
{
if (tree[rt]==r-l+1) return ;
if (L<=l && r<=R){
for (int i=l;i<=r;i++) increase[i]=true;
tree[rt] = r-l+1;
return ;
}
if (tree[rt]==r-l+1) push_down(rt,r-l+1);
mid;
if (L<=m) update(L,R,lson);
if (R >m) update(L,R,rson);
push_up(rt);
}
bool flag;///表示当前是否可以存在该递减区间
void query(int L,int R,int rt,int l,int r)///判断询问的线段是否全在递增区间,记得R-1
{
if (flag) return ;
if (L<=l && r<=R){
if (tree[rt]!=r-l+1) flag = true;
return ;
}
if (tree[rt]==r-l+1) push_down(rt,r-l+1);
mid;
if (L<=m) query(L,R,lson);
if (R >m) query(L,R,rson);
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d %d %d",op+i,l+i,r+i);
}
for (int i=1;i<=m;i++)
if (op[i]==1) update(l[i],r[i]-1,1,1,n);
flag = true;///防止一次也没出现
for (int i=1;i<=m;i++){
if (op[i]==0){
flag = false;
query(l[i],r[i]-1,1,1,n);
if (!flag) break;
}
}
if (!flag) printf("NO\n");
else {
bool blank = false;
printf("YES\n");
int now = n;
for (int i=1;i<n;i++){
if (increase[i]){
int renow = now;
now -= 2;
while (increase[i+1]){now--;i++;}
for (int j=now+1;j<=renow;j++){
if (!blank) blank = true;
else printf(" ");
printf("%d",j);
}
}
else if (!increase[i]){
if (!increase[i-1]){
if (!blank) blank = true;
else printf(" ");
printf("%d",now--);
}
if (i==n-1) printf(" %d",now--);
}
}
}
return 0;
}