A. Suits
题目链接
给你a条领带,b条围巾,c件背心,d件夹克。一条领带和一件夹克可以组成第一类西装,价值为e。一条围巾和一件背心和一件夹克可以组成第二类西装,价值为f。问最多能组成多少价值。
数据范围:
1
≤
a
≤
1
0
5
1\leq a\leq 10^5
1≤a≤105,
1
≤
b
≤
1
0
5
1\leq b\leq 10^5
1≤b≤105,
1
≤
c
≤
1
0
5
1\leq c\leq 10^5
1≤c≤105,
1
≤
d
≤
1
0
5
1\leq d\leq 10^5
1≤d≤105,
1
≤
e
≤
1
0
3
1\leq e\leq 10^3
1≤e≤103,
1
≤
f
≤
1
0
3
1\leq f\leq 10^3
1≤f≤103
解:两种西装都需要一件夹克,所以夹克先给价值高的用,如果多了再给价值低的用。
复杂度:
O
(
1
)
O(1)
O(1)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
int a,b,c,d,e,f;
scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f);
int ans=0;
if(e>f){
ans+=min(a,d)*e;
d-=min(a,d);
int k=b;
k=min(k,c);
k=min(k,d);
ans+=k*f;
}else{
int k=b;
k=min(k,c);
k=min(k,d);
d-=k;
ans+=k*f;
ans+=min(a,d)*e;
}
printf("%d\n",ans);
}
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
T=1;
while(T--){
work();
}
}
B. Blocks
题目链接
给你一个长度为n的字符串,只包含B和W两种字符,你可以选择两个相邻的字符,使这两个字符B变W,W变B,问能否在3*n的操作内使所有字符相同,不能输出-1,能的话要求输出操作的数量即位置( 值代表操作这个位置和他右边这个位置)。
数据范围:
2
≤
n
≤
200
2\leq n \leq 200
2≤n≤200
解:显然,每一次操作会使两种字符的数量变化偶数个。所以只要判断2种字符的数量是否是偶数即可,然后暴力找操作位置。
复杂度:
O
(
n
)
O(n)
O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[205];
void work()
{
int n;
scanf("%d",&n);
scanf("%s",a);
int x=0;
int y=0;
for(int i=0;i<strlen(a);i++){
if(a[i]=='B'){
x++;
}else{
y++;
}
}
if(x%2==1&&y%2==1){
printf("-1\n");
return;
}
vector<int>v;
if(x%2==0){
for(int i=0;i<strlen(a)-1;i++){
if(a[i]=='B'){
v.push_back(i);
a[i]='W';
if(a[i+1]=='B'){
a[i+1]='W';
}else{
a[i+1]='B';
}
}
}
}else{
for(int i=0;i<strlen(a)-1;i++){
if(a[i]=='W'){
v.push_back(i);
a[i]='B';
if(a[i+1]=='B'){
a[i+1]='W';
}else{
a[i+1]='B';
}
}
}
}
printf("%d\n",v.size());
for(int i=0;i<v.size();i++){
printf("%d ",v[i]+1);
}
printf("\n");
}
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
T=1;
while(T--){
work();
}
}
C. Shawarma Tent
题目链接
给一个矩形网格,给出学校位置sx,sy,然后给出n个学生的家x,y。你要在一个地方修一个帐篷,如果有学生到学校的任意最短路径会经过帐篷,则值+1,输出最大值,并输出帐篷位置。
数据范围:
1
≤
n
≤
2
∗
1
0
5
1\leq n \leq 2*10^5
1≤n≤2∗105,
0
≤
s
x
,
s
y
≤
1
0
9
0\leq s_x,s_y \leq 10^9
0≤sx,sy≤109,
0
≤
x
i
,
y
i
≤
1
0
9
0\leq x_i,y_i \leq 10^9
0≤xi,yi≤109
解:显然答案会在
(
s
x
+
1
,
s
y
)
(sx+1,sy)
(sx+1,sy)、
(
s
x
−
1
,
s
y
)
(sx-1,sy)
(sx−1,sy)、
(
s
x
,
s
y
+
1
)
(sx,sy+1)
(sx,sy+1)、
(
s
x
,
s
y
−
1
)
(sx,sy-1)
(sx,sy−1)这四个值中取到。那么枚举每一个学生和学校的相对位置,判断可以经过哪几个点,最后取最大值即可。
复杂度
O
(
n
)
O(n)
O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
int n,sx,sy;
int a=0,b=0,c=0,d=0;
scanf("%d%d%d",&n,&sx,&sy);
for(int i=1;i<=n;i++){
int x,y;
scanf("%d%d",&x,&y);
if(x<sx){
if(y<sy){
a++;
b++;
}
if(y>sy){
b++;
c++;
}
if(y==sy){
b++;
}
}
if(x==sx){
if(y<sy){
a++;
}else{
c++;
}
}
if(x>sx){
if(y<sy){
a++;
d++;
}
if(y==sy){
d++;
}
if(y>sy){
c++;
d++;
}
}
}
int maxx=a;
maxx=max(maxx,max(b,max(c,d)));
printf("%d\n",maxx);
if(maxx==a){
printf("%d %d\n",sx,sy-1);
}else if(maxx==b){
printf("%d %d\n",sx-1,sy);
}else if(maxx==c){
printf("%d %d\n",sx,sy+1);
}else printf("%d %d\n",sx+1,sy);
}
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
T=1;
while(T--){
work();
}
}
D. Portals
题目链接
有n座城堡,每座城堡需要
a
i
a_i
ai个人才能进入,进入城后可以招募到
b
i
b_i
bi个人,如果城堡中驻扎有人,那么可以获得
c
i
c_i
ci的贡献。给出m条边,连着2个城堡
u
,
v
,
u
>
v
u,v,u>v
u,v,u>v,你可以在到达城堡时派一个人驻扎在该城,或者在到达u城时派一个人到v城驻扎。(不能连着通过2条边)你必须按顺序进入n个城,并且必须到达第n个城并进入。初始你拥有k个人,问你能获得的最大贡献。
输入 n,m,k,然后n个城堡的
a
i
,
b
i
,
c
i
a_i,b_i,c_i
ai,bi,ci,然后m条边
u
i
,
v
i
u_i,v_i
ui,vi
数据范围
1
≤
n
≤
5000
1\leq n\leq 5000
1≤n≤5000,
1
≤
m
≤
m
i
n
(
n
∗
(
n
−
1
)
2
,
3
∗
1
0
5
)
1\leq m\leq min(\frac{n*(n-1)}{2},3*10^5)
1≤m≤min(2n∗(n−1),3∗105),
0
≤
k
≤
5000
0\leq k\leq 5000
0≤k≤5000,
0
≤
a
i
,
b
i
,
c
i
≤
5000
0\leq a_i,b_i,c_i\leq 5000
0≤ai,bi,ci≤5000,
1
≤
v
i
≤
u
i
≤
n
1\leq v_i\leq u_i\leq n
1≤vi≤ui≤n,
k
+
∑
i
=
1
n
b
i
≤
5000
k+\sum_{i=1}^{n}b_i\leq 5000
k+∑i=1nbi≤5000
解:(辣鸡题意,没发样例解释前完全没看懂)
对于每一个城来说,从越靠近n的城派人过去越优,故首先开一个数组代表这个城可以最迟从哪个城派人过来,初始化为
i
i
i,然后遍历所有边,把值更新至最大,即该城最迟可以在哪个地方派人过去。
我们可以很简单的求出到达每一个城的人数,再减去下个城进入所需要的人数,那么我们就可以求出在每个城可以派出去的人数。以每个城可以派出去的人数建一棵线段树,维护最小值,然后将城堡按照贡献从大到小排序,遍历
i
i
i,从该城最迟派人的地方到n区间-1,然后判断
0
≤
m
i
n
0\leq min
0≤min,如果成立,则加入贡献,否则将1加回。
复杂度
O
(
n
∗
log
n
)
O(n*\log n)
O(n∗logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
int id;
int a;
int b;
int c;
}num[5005];
int ans[5005];
int vis[5005];
bool cmp(node x,node y)
{
if(x.c!=y.c)return x.c>y.c;
else return vis[x.id]>vis[y.id];
}
int tr[5005<<2];
int lazy[5005<<2];
void build(int l,int r,int rt)
{
if(l==r){
tr[rt]=ans[l];
//printf("%d %d\n",l,tr[l]);
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
tr[rt]=min(tr[rt<<1],tr[rt<<1|1]);
}
void pushdown(int rt)
{
if(lazy[rt]){
tr[rt<<1]+=lazy[rt];
tr[rt<<1|1]+=lazy[rt];
lazy[rt<<1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
lazy[rt]=0;
}
}
void update(int l,int r,int rt,int L,int R,int C)
{
if(L<=l&&R>=r){
tr[rt]+=C;
lazy[rt]+=C;
return;
}
pushdown(rt);
int m=(l+r)>>1;
if(L<=m)update(l,m,rt<<1,L,R,C);
if(R>m)update(m+1,r,rt<<1|1,L,R,C);
tr[rt]=min(tr[rt<<1],tr[rt<<1|1]);
}
int query(int l,int r,int rt,int L,int R)
{
if(L<=l&&R>=r){
return tr[rt];
}
pushdown(rt);
int ans=99999;
int m=(l+r)>>1;
if(L<=m)ans=min(ans,query(l,m,rt<<1,L,R));
if(R>m)ans=min(ans,query(m+1,r,rt<<1|1,L,R));
return ans;
}
void work()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&num[i].a,&num[i].b,&num[i].c);
num[i].id=i;
vis[i]=i;
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
vis[y]=max(vis[y],x);
}
ans[0]=k;
int summ=k;
num[n+1].a=0;
for(int i=1;i<=n;i++){
if(summ<num[i].a){
printf("-1\n");
return;
}
summ+=num[i].b;
ans[i]=summ-num[i+1].a;
}
build(1,n,1);
sort(num+1,num+n+1,cmp);
int sum=0;
for(int i=1;i<=n;i++){
update(1,n,1,vis[num[i].id],n,-1);
if(query(1,n,1,1,n)>=0){
sum+=num[i].c;
}else{
update(1,n,1,vis[num[i].id],n,1);
}
}
printf("%d\n",sum);
}
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
T=1;
while(T--){
work();
}
}
E. Common Number
题目链接
对于每个数给出一个操作:如果n为偶数,则
n
=
n
/
2
n=n/2
n=n/2,否则
n
=
n
−
1
n=n-1
n=n−1,将得到的数放入path数组,例如
p
a
t
h
(
32
)
=
[
32
,
16
,
8
,
4
,
2
,
1
]
path(32)=[32,16,8,4,2,1]
path(32)=[32,16,8,4,2,1]。
现在给你n和k,求最大的ans使得从1到n的path中含有ans的数的数量大于等于k。
数据范围
1
≤
k
≤
n
≤
1
0
18
1\leq k \leq n \leq 10^{18}
1≤k≤n≤1018
正解 对于每一个数,我们可以求出从1到n有多少个含有它,这个值在奇偶上分别满足单调性,故奇数进行二分,偶数进行二分,求最大值即可。
复杂度
O
(
log
n
)
O(\log n)
O(logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll sum(ll x)
{
ll p2=1;
ll ans=0;
while(p2*x<=n){
ll hi=min(n,p2*(x+1)-1);
ans+=hi-p2*x+1;
p2*=2;
}
return ans;
}
ll ok(ll x)
{
if(x%2==0){
//printf("%lld %lld %lld\n",x,sum(x)+sum(x+1));
return sum(x)+sum(x+1);
}else{
//printf("%lld %lld\n",x,sum(x));
return sum(x);
}
}
void work()
{
scanf("%lld%lld",&n,&k);
ll ans=1;
ll l=1;
ll r=(n+1)/2;
while(l<=r){
ll m=(l+r)>>1;
if(ok(m*2-1)>=k)l=m+1;
else r=m-1;
}
ans=max(ans,r*2-1);
l=1;
r=n/2;
while(l<=r){
ll m=(l+r)>>1;
if(ok(m*2)>=k)l=m+1;
else r=m-1;
}
ans=max(ans,r*2);
printf("%lld\n",ans);
}
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
T=1;
while(T--){
work();
}
}
贪心解 显然,最后的答案与n不断除二得到的值比较接近,故可以贪心暴力求解。
复杂度
O
(
20
∗
log
n
)
O(20*\log n)
O(20∗logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll sum(ll x)
{
ll p2=1;
ll ans=0;
while(p2*x<=n){
ll hi=min(n,p2*(x+1)-1);
ans+=hi-p2*x+1;
p2*=2;
}
return ans;
}
ll ok(ll x)
{
if(x%2==0){
//printf("%lld %lld %lld\n",x,sum(x)+sum(x+1));
return sum(x)+sum(x+1);
}else{
//printf("%lld %lld\n",x,sum(x));
return sum(x);
}
}
void work()
{
scanf("%lld%lld",&n,&k);
ll ans=1;
ll cn=n;
while(cn){
for(int i=0;i<=20;i++){
if(cn<i)break;
if(ok(cn-i)>=k){
ans=max(ans,cn-i);break;
}
}
cn/=2;
}
printf("%lld\n",ans);
}
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
T=1;
while(T--){
work();
}
}
F,不想补了。。。