1013A Piles With Stones
题意
最初有
n
n
堆石子,状态为 ,现想要变成
bi
b
i
,问可不可行
每次操作可以讲一颗石子从一堆拿到另一堆,或者拿走一颗石子
题解
显然如果能就代表原来的个数大于等于现在的….
代码
#include <cstdio>
#define N 55
//int a[N],b[N];
int n,sum1=0,sum2=0;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
sum1+=x;
}
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
sum2+=x;
}
if(sum1>=sum2) printf("Yes");
else printf("No");
return 0;
}
1013B And
题意
有
n
n
个数 和一个数
x
x
,每次操作可以将一些数与 进行 & 操作
问多少次后会出现有两个数相同的情况
题解
显然两个数相同,只有三种情况:原本就一样;一个数取&和另一个数一样了;两个数都取&以后一样了
很简单的题改了好久【再见】
代码
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100010
int n,m,a[N],cnt[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(cnt[a[i]]){printf("0\n");return 0;}
cnt[a[i]]++;
}
for(int i=1;i<=n;i++){
--cnt[a[i]];
if(cnt[a[i]&m]){printf("1\n");return 0;}
++cnt[a[i]];
}
for(int i=1;i<=n;i++){
--cnt[a[i]];
if(cnt[a[i]&m]){printf("%d\n",2);return 0;}
++cnt[a[i]&m];
}
printf("-1\n");
return 0;
}
1013C/1012A Photo of The Sky
题意
给你2n个数,任意组合得到n个坐标,求最小矩形面积能够框住这n个点。
题解
显然贪心吧…肯定里的越近越好
最大值只有两种情况
第一种:x从
a1
a
1
开始,结束在
[an,an∗2)
[
a
n
,
a
n
∗
2
)
第二种:x属于
a1
a
1
到
an∗2
a
n
∗
2
,y为其中一段
代码
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 200010
#define ll long long
int n,m;
ll a[N];
ll sum=(ll)1e18;
int main(){
// freopen("a.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n<<1;i++) scanf("%I64d",&a[i]);
sort(a+1,a+(n<<1)+1);
for(int i=n;i<=(n<<1)-1;i++){
ll x=(a[i]-a[1])*(a[n<<1]-a[2*n-i+1]);
sum=min(x,sum);
}
for(int i=2;i<=n;i++){
ll x=(a[n<<1]-a[1])*(a[i+n-1]-a[i]);
sum=min(x,sum);
}
printf("%I64d\n",sum);
return 0;
}
1013D/1012B Chemical table
题意
n∗m
n
∗
m
的格子,其中有一部分已经被选。
若这个格子中
(l1,r1)、(l1,r2)、(l2,r1)
(
l
1
,
r
1
)
、
(
l
1
,
r
2
)
、
(
l
2
,
r
1
)
已被选,则
(l2,r2)
(
l
2
,
r
2
)
也被选了
问最少需要再选多少个格子才能使所有格子都被选上
题解
把行、列变成点,连起来求联通块个数就好啦….
因为如果这个两行之间的同一列有点,那么剩下这两行中有点的列就会都有点了
注意结果要减1,因为有一个连通块可以理解为最初连通块,显然使不能够算的
代码
#include <cstdio>
#define N 400010
int n,m,q,ans=-1,fa[N];
int find(int x){
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
int main(){
// freopen("d.in","r",stdin);
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n+m;i++) fa[i]=i;
for(int i=1;i<=q;i++){
int x,y;scanf("%d%d",&x,&y);
int xx=find(x),yy=find(y+n);
if(xx!=yy) fa[xx]=yy;
}
for(int i=1;i<=n+m;i++) if(find(i)==i) ans++;
printf("%d\n",ans);
return 0;
}
1013E/1012C Hills
题意
要在
n
n
个房子中选出 ~
n2
n
2
个房子,要求选出的房子都要比它旁边两高。
每次操作可以把其中一间房子变矮
1
1
问选出 ~
n2
n
2
间房子分别需要最少几步
题解
显然是个dp…
设
dp[i][j][0/1]
d
p
[
i
]
[
j
]
[
0
/
1
]
表示前i个房子选了j个房子,第i个房子选或不选(0为不选,1为选)的最少步数
dp[i][j][0]=min(dp[i−1][j][0],dp[i−1][j][1])
d
p
[
i
]
[
j
]
[
0
]
=
m
i
n
(
d
p
[
i
−
1
]
[
j
]
[
0
]
,
d
p
[
i
−
1
]
[
j
]
[
1
]
)
dp[i][j][1]=min(dp[i−2][j−1][0]+s1,dp[i−2][j−1][1]+s2)
d
p
[
i
]
[
j
]
[
1
]
=
m
i
n
(
d
p
[
i
−
2
]
[
j
−
1
]
[
0
]
+
s
1
,
d
p
[
i
−
2
]
[
j
−
1
]
[
1
]
+
s
2
)
s1=max(0,h[i−1]−h[i]+1)+max(0,h[i+1]−h[i]+1)
s
1
=
m
a
x
(
0
,
h
[
i
−
1
]
−
h
[
i
]
+
1
)
+
m
a
x
(
0
,
h
[
i
+
1
]
−
h
[
i
]
+
1
)
s2=max(0,min(h[i−2],h[i−1]+1)−h[i])+max(0,h[i+1]−h[i]+1)
s
2
=
m
a
x
(
0
,
m
i
n
(
h
[
i
−
2
]
,
h
[
i
−
1
]
+
1
)
−
h
[
i
]
)
+
m
a
x
(
0
,
h
[
i
+
1
]
−
h
[
i
]
+
1
)
注:s2这里wa了两发【捂脸】
因为s2要考虑
h[i−2]
h
[
i
−
2
]
与
h[i]
h
[
i
]
,如果
h[i−2]<=h[i−1]
h
[
i
−
2
]
<=
h
[
i
−
1
]
,那么就是从
h[i−1]
h
[
i
−
1
]
减了,然而如果
h[i−1]>h[i−2]
h
[
i
−
1
]
>
h
[
i
−
2
]
,此时
h[i−1]=h[i−2]−1
h
[
i
−
1
]
=
h
[
i
−
2
]
−
1
代码
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 5010
int n,f[N][N<<1][2],h[N];
int main(){
// freopen("a.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
memset(f,inf,sizeof(f));
f[1][1][1]=max(0,h[2]-h[1]+1);
f[1][0][0]=f[0][0][0]=0;
for(int i=2;i<=n;i++){
f[i][0][0]=0;
for(int j=1;j<=(i+1>>1);j++){
f[i][j][0]=min(f[i-1][j][0],f[i-1][j][1]);
f[i][j][1]=min(f[i-2][j-1][0]+max(0,h[i-1]-h[i]+1)+max(0,h[i+1]-h[i]+1),
f[i-2][j-1][1]+max(0,min(h[i-2],h[i-1]+1)-h[i])+max(0,h[i+1]-h[i]+1));
}
}
for(int i=1;i<=(n+1>>1);i++) printf("%d ",min(f[n][i][0],f[n][i][1]));
return 0;
}