A : TT 的袜子
题目描述
TT 有一屋子的袜子,总共有
n
n 只,袜子有
k
k 种颜色,每天 TT 都要穿两只颜色相同的袜子,这一天结束后 TT 会丢弃今天的袜子。
现在输入所有袜子的颜色,输出 TT 的袜子可以坚持用多少天。
输入描述
第一行输入
n
,
k
n,k (
1
≤
n
,
k
≤
1000
1≤n,k≤1000)。
第二行输入
n
n 个数,第
i
i 个数
c
i
c
i
表示第
i
i 只袜子的颜色(
1
≤
c
i
≤
k
1≤c
i
≤k)。
输出描述
输出一个数,表示答案。
输入样例
10 5
1 2 1 3 1 5 4 4 2 2
输出样例
3
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
vector<int> vtr;
int n,k;
cin>>n>>k;
int num;
for(int l=0;l<n;l++)
{cin>>num;vtr.push_back(num);}
sort(vtr.begin(),vtr.end());
int i=0;
int j=1;
int ans=0;
while(j<n)
{
if(vtr[i]==vtr[j])
{ ans++;
i+=2;
j+=2;
}
else
{i++,j++;
}
}
cout<<ans<<endl;
}
B : 定价
题目描述
有
n
n 个人买东西同一个商品,第
i
i 个人认为合理的价格区间
[
l
i
,
r
i
]
[l
i
,r
i
],表示如果价格低于
l
l 嫌便宜,如果价格高于
r
r 嫌贵。
请你设计商品的价格,使在满足尽可能多的人认为价格合理的条件下,商品价格最高。具体来说,你需要输出最终商品的定价与认为价格合理的人数。
输入描述
第一行输入一个整数
n
(
1
≤
n
≤
1
0
6
)
n(1≤n≤10
6
),表示人数。
接下来
n
n 行,第
i
i 行输入两个数
l
i
,
r
i
l
i
,r
i
(
1
≤
l
i
≤
r
i
≤
1
0
6
)
(1≤l
i
≤r
i
≤10
6
),表示第
i
i 个人认为的价格合理的区间。
输出描述
输出一行两个整数,以一个空格分割,分别表示最终商品的定价与认为价格合理的人数。
输入样例
5
1 3
2 4
2 3
3 4
4 5
输出样例
3 4
子任务
存在
70
%
70% 的测试数据,
n
≤
1000
,
∀
i
,
l
i
≤
r
i
≤
1000
n≤1000 , ∀i,l
i
≤r
i
≤1000
对于所有的测试数据,
1
≤
n
≤
1
0
6
1≤n≤10
6
,
∀
i
,
1
≤
l
i
≤
r
i
≤
1
0
6
∀i,1≤l
i ≤r i ≤10 6
#include <iostream>
#include <map>
using std::pair;
using std::map;
int main()
{
int n;
map<int, int> areas;
pair<int, int> *ps;
scanf("%d", &n);
ps = new pair<int, int>[n];
for (int i = 0; i < n; i++)
{
int l, r;
scanf("%d %d", &l, &r);
ps[i].first = l;
ps[i].second = r;
areas.insert(pair<int, int>(l, 0));
areas.insert(pair<int, int>(r, 0));
}
for (int i = 0; i < n; i++)
{
areas.find(ps[i].first)->second += 1;
map<int, int>::iterator end = areas.find(ps[i].second);
end++;
if (end != areas.end())
end->second -= 1;
}
int p = 0;
int c = 0;
int mc = 0;
for (map<int, int>::iterator it = areas.begin(); it != areas.end(); it++)
{
mc += it->second;
if (mc >= c)
{
c = mc;
p = it->first;
}
}
printf("%d %d\n", p, c);
}
C : 吃包子
问题描述
来来来,尝尝新出炉的包子啊!
小
L
L 和小
W
W 买了
n
n 个包子排成一行,用
s
i
s
i
表示第
i
i 个包子的大小,并且包子大小最大值是
x
x。
小
W
W 是个挑剔的人,小
W
W 只肯按照包子大小不递减的顺序吃包子。
现在小
L
L 会负责吃掉大小
s
i
s
i
处在
[
l
,
r
]
[l,r] 范围内的所有的包子,之后小
W
W 会按照包子标号从小到大依次吃掉剩下的包子,如果剩下的包子没有满足不递减的顺序,小
W
W 会不肯吃。
现在小
L
L 想知道有多少种
[
l
,
r
]
[l,r] 的方案可以让小
W
W 肯吃包子。
一个合法的
[
l
,
r
]
[l,r] ,
l
l 和
r
r 必须都是
1
≤
l
≤
r
≤
x
1≤l≤r≤x 的整数
输入格式
第一行一个整数
n
,
x
n,x ,表示有
n
n 个包子,包子的最大大小为
x
x。
1
≤
n
,
x
≤
1
0
6
1≤n,x≤10
6
接下来一行,有
n
n 个数,第
i
i 个数
s
i
s
i
表示第
i
i 个包子的大小。
1
≤
s
i
≤
x
1≤s
i
≤x
输出格式
输出一行,一个整数表示方案数。
样例输入
5 4
1 3 2 4 2
样例输出
7
样例解释
[
1
,
2
]
[1,2] : 去掉数值处在范围
[
1
,
2
]
[1,2] 的数值之后,剩余数列为
{
3
,
4
}
{3,4} ,是非递减数列
[
1
,
3
]
[1,3] : 去掉数值处在范围
[
1
,
3
]
[1,3] 的数值之后,剩余数列为
{
4
}
{4} ,是非递减数列
[
1
,
4
]
[1,4] : 去掉数值处在范围
[
1
,
4
]
[1,4] 的数值之后,剩余数列为
{
}
{} ,是非递减数列
[
2
,
2
]
[2,2] : 去掉数值处在范围
[
2
,
2
]
[2,2] 的数值之后,剩余数列为
{
1
,
3
,
4
}
{1,3,4} ,是非递减数列
[
2
,
3
]
[2,3] : 去掉数值处在范围
[
2
,
3
]
[2,3] 的数值之后,剩余数列为
{
1
,
4
}
{1,4} ,是非递减数列
[
2
,
4
]
[2,4] : 去掉数值处在范围
[
2
,
4
]
[2,4] 的数值之后,剩余数列为
{
1
}
{1} ,是非递减数列
[
3
,
4
]
[3,4] : 去掉数值处在范围
[
3
,
4
]
[3,4] 的数值之后,剩余数列为
{
1
,
2
,
2
}
{1,2,2} ,是非递减数列
共有
7
7 种方案。
数据范围
对于
30
%
30% 的数据,满足
1
≤
n
,
x
≤
500
1≤n,x≤500
对于
80
%
80% 的数据,满足
1
≤
n
,
x
≤
5000
1≤n,x≤5000
对于
100
%
100% 的数据,满足
1
≤
n
,
x
≤
1
0
6
1≤n,x≤10
6
#include <bits/stdc++.h>
using namespace std;
const long long N = 1000010;
void in(long long &x){
cin>>x;
}
void o(long long x){
cout<<x;
}
long long n,x;
long long cnt;//逆序数量
long long a[N],dp[N];//包子,最小的右端点
set<long long>st;//当前数组
vector<long long>g[N];// g[i]中包含重量为i的所有的包子的位置
void Add(long long x){// 把大小为x的包子加入数组中
for(long long i=0;i<g[x].size();i++){
auto it = st.lower_bound(g[x][i]);
long long last=-1,next = -1;
if(it!=st.end())next=*(it);
if(it!=st.begin())it--,last=*(it);
if(next!=-1&&last!=-1){
if(a[next]<a[last])cnt--;
if(x<a[last])cnt++;
if(a[next]<x)cnt++;
}else if(next!=-1){
if(a[next]<x)cnt++;
}else if(last!=-1){
if(x<a[last])cnt++;
}
st.insert(g[x][i]);
}
}
void Drop(long long x){// 将大小为x的包子从数组中删去
for(long long i=0;i<g[x].size();i++){
auto it = st.lower_bound(g[x][i]);
long long next = -1,last = -1;
it++;if(it!=st.end())next = *(it);
it--;
if(it!=st.begin()){
it--;
last = *(it);
it++;
}
if(last!=-1){
if(a[last]>x)cnt--;
}
if(next!=-1){
if(a[next]<x)cnt--;
}
if(next!=-1&&last!=-1){
if(a[next]<a[last])cnt++;
}
st.erase(g[x][i]);
}
}
bool check(){
return cnt==0;
}
signed main(){
in(n);in(x);
for(long long i=1;i<=n;i++){
in(a[i]);
g[a[i]].push_back(i);//将下标i加入到g[a[i]]中
}
for(long long i=1;i<=x;i++)Add(i);// 把所有包子加进去
long long r = 1;
for(long long i=1;i<=x;i++){
Add(i-1);//左端点i加了1,删除重量为i-1的包子
if(r==i){//特判一下,右端点不能等于左端点
Drop(r);//删掉r
r++;
}
while(!check()){
if(r==x+2)break;//没有有r与i对应了,退出循环
Drop(r);r++;//删掉r
}
dp[i]=r-1;//记录答案
}
long long ans=0;//统计答案
for(long long i=1;i<=x;i++){
ans+=(x-dp[i]+1);
}
o(ans);
putchar('\n');
return 0;
}
思路
TT的袜子
统计某种颜色的袜子个数;
天数=每种颜色袜子个数/2 求和。
第二题
将区间边界转换成点,对所有点进行排序,扫描排序结果。当遇到起点时,重叠个数加一,并且记录重叠个数的最大值;当遇到止点时,重叠个数减一。
吃包子在这俩基础上得加一些东西,