0%

Codeforces Round#645 div.2

A

题意

n*m的矩阵 可以在任意一条边上放灯 灯可以照到边连着的小矩形 问最少需要几盏灯能点亮整个矩阵

题解

实际上推理一下就可以看出来了 每两个小矩形需要一盏灯 如果最后是单个的还需要一盏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
int ans=n*m/2;
if((n*m)%2){
++ans;
}
printf("%d\n",ans);
}
return 0;
}

B

题意

有n+1个granny 一开始只有一个granny在场地 她可以一次叫任意个granny 但每个granny有自己的人数要求 如果她来的时候人数不达标她就会走 人数包括同时喊来的其他人但不包括她自己 问最多能聚集几个granny

题解

也很简单 按照要求聚集人数来存 然后逐个求sum 如果sum[i]>i那么就说明是能够达到这个数字的 求满足条件的最大的sum[i]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gran[200020],su[200020];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
int tmp;
memset(gran,0,sizeof(gran));
memset(su,0,sizeof(su));
gran[0]=su[0]=1;
for(int i=0;i<n;++i){
scanf("%d",&tmp);
++gran[tmp];
}
int ans=1;
for(int i=1;i<=n;++i){
su[i]=su[i-1]+gran[i];
if(su[i]>i){
ans=su[i];
}
}
printf("%d\n",ans);
}
return 0;
}

C

题意

给一个矩阵 定义方式见题 问从x1,y1到x2,y2的的路径和有多少种可能 只能向下或向右走

题解

给的矩阵很容易看出 向下的值比向右的值大1 也就是一次向下和向右操作的颠倒会差1 推理一下很容易发现 可能的路径和是下限到上限的所有值 下限是一直向右最后向下 上限是一直向下最后向右 再计算一下就能推出差值实际上就是(x2-x1)*(y2-y1) 宽度决定一个差1会积累几次 高度决定积累几个差1 最后答案就是差值+1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int main(){
int T;
scanf("%d",&T);
while(T--){
long long x1,x2,y1,y2;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
long long tmp=(x2-x1)*(y2-y1);
long long res=tmp+1;
printf("%lld\n",res);
}
return 0;
}

D

题意

一年n个月 一个月ki天 每天的拥抱值是所在月份的天数 要选连续的x天 问怎么选能让拥抱值最大 可以跨年

题解

跨年问题很好解决 我们计算两年的就可以了 而后我们可以证明 答案的右边界一定是卡着月份结束的 反证法可以推出来 当然做题时候就是靠感觉了 然后只要试每个边界就完了

然而我写的tle了。。用了二分查找依旧tle。。方法写的还是不太好看起来。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
long long month[400020],su[400020];
long long last(int t){
long long tmpindex;
while(tmpindex=(upper_bound(su,su+n+1,t)-su),tmpindex!=(n+1)){
return su[tmpindex]-t;
}
return 0;
}
long long val(long long start,long long len){
long long res=0,las=0,tmpindex;
while(tmpindex=(upper_bound(su,su+n+1,start)-su),tmpindex!=(n+1)){
if(len==0){
break;
}
int i=tmpindex;
long long tmplen=min(len,su[i]-start);
las=0;
if(i!=0){
las=su[i-1];
}
long long calst=start-las+1;
res+=(calst+calst+tmplen-1)*tmplen/2;
start+=tmplen;
len-=tmplen;
}
// for(int i=0;i<=n;++i){
// if(len==0){
// break;
// }
// if(su[i]>start){
// long long tmplen=min(len,su[i]-start);
// long long calst=start-las+1;
// res+=(calst+calst+tmplen-1)*tmplen/2;
// start+=tmplen;
// len-=tmplen;
// }
// las=su[i];
// }
return res;
}
int main(){
int x;
scanf("%d%d",&n,&x);
for(int i=0;i<n;++i){
scanf("%lld",&month[i]);
month[n+i]=month[i];
}
n=n*2;
su[0]=month[0];
for(int i=0;i<n;++i){
su[i+1]=su[i]+month[i+1];
}
long long ans=val(0,x),start=0,las=x;
long long res=ans;
long long tmp=0;
while(tmp=last(las)){
ans-=val(start,tmp);
ans+=val(las,tmp);
res=max(res,ans);
start+=tmp;
las+=tmp;
}
printf("%lld\n",res);
return 0;
}