AtCoder Regular Contest 112 Summary
A - B = C:统计+数学
考虑固定
C
C
C,即
A
=
B
+
C
A=B+C
A=B+C。
∵
A
=
B
+
C
≤
R
,
∴
L
≤
B
≤
R
−
C
.
∴
L
≤
C
≤
R
−
L
.
\because A=B+C\leq R,\\ \therefore L\leq B\leq R-C.\\ \therefore L\leq C\leq R-L.\\
∵A=B+C≤R,∴L≤B≤R−C.∴L≤C≤R−L.
答案就为
∑
i
=
L
R
−
L
R
−
i
−
L
+
1
\sum_{i=L}^{R-L}{R-i-L+1}
∑i=LR−LR−i−L+1。
化简一下:
∑
i
=
L
R
−
L
R
−
i
−
L
+
1
=
(
R
−
L
+
1
)
(
R
−
2
L
+
1
)
−
∑
i
=
L
R
−
L
i
=
(
R
−
L
+
1
)
(
R
−
2
L
+
1
)
−
(
R
−
L
+
L
)
(
R
−
2
L
+
1
)
2
=
(
R
−
L
+
1
)
(
R
−
2
L
+
1
)
−
R
(
R
−
2
L
+
1
)
2
\sum_{i=L}^{R-L}{R-i-L+1}\\ =(R-L+1)(R-2L+1)-\sum_{i=L}^{R-L}{i}\\ =(R-L+1)(R-2L+1)-\frac{(R-L+L)(R-2L+1)}{2}\\ =(R-L+1)(R-2L+1)-\frac{R(R-2L+1)}{2}\\
i=L∑R−LR−i−L+1=(R−L+1)(R−2L+1)−i=L∑R−Li=(R−L+1)(R−2L+1)−2(R−L+L)(R−2L+1)=(R−L+1)(R−2L+1)−2R(R−2L+1)
直接算即可,注意 R − L < L R-L<L R−L<L的情况。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll T,l,r;
int main(){
cin>>T;
for (;T;T--){
cin>>l>>r;
if (r-l<l){
printf("0\n");
continue;
}
ll sum=r*(r-l-l+1)/2;
printf("%lld\n",(r-l+1)*(r-l-l+1)-sum);
}
return 0;
}
B - – - B:分类+数学
分类讨论。
我是在数轴上考虑的。
仔细讨论即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll b,c;
int main(){
scanf("%lld%lld",&b,&c);
if (b<0){
if (abs(b)<c){
if (c<=abs(b)*2) printf ("%lld",c*2-1);
else printf ("%lld",c+2*abs(b));
}
else if (abs(b)==c){
if (c>1) printf ("%lld",c*2-1);
else printf ("%lld",2);
}
else{
printf ("%lld",c*2-1);
}
}
else if (b==0){
printf ("%lld",c);
}
else{
if (b<c){
if (c<=b*2-1) printf("%lld",c*2-1);
else printf ("%lld",abs(-b-c/2)*2-(!(c&1)));
}
else{
if(c==1) printf("2");
else printf ("%lld",c*2-1);
}
}
return 0;
}
C - DFS Game:动态规划+树+贪心
设 f x f_x fx表示以 x x x为根的子树先手与后手的金币差, s z x sz_x szx表示子树大小。
我们可以递归解决问题。
设 y ∈ s o n x y\in son_x y∈sonx,分三种情况:
- f y < 0 , s z y ≡ 0 ( m o d 2 ) f_y<0,sz_y\equiv0(\mod 2) fy<0,szy≡0(mod2),这样后手会将所有这样的结点都选一遍。
- f y ≥ 0 , s z y ≡ 0 ( m o d 2 ) f_y\ge 0,sz_y\equiv0(\mod2) fy≥0,szy≡0(mod2),这样后手要避免选择 y y y。
- s z y ≡ 1 ( m o d 2 ) sz_y\equiv1(\mod 2) szy≡1(mod2),这样的话后手每次都要选择较小的 f y f_y fy。
这样的话,我们每一次把这些 f f f存起来排序,就用 O ( n log 2 n ) O(n\log_2^n) O(nlog2n)的时间复杂度算出来了。
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,sz[N],f[N],la[N],to[N],ne[N],cnt=0,b[N];
void add(int x,int y){
to[++cnt]=y;
ne[cnt]=la[x];
la[x]=cnt;
}
void dfs(int x){
sz[x]=1;
f[x]=1;
for (int i=la[x];i;i=ne[i]){
int y=to[i];
dfs(y);
}
int len=0,sum=0;
for (int i=la[x];i;i=ne[i]){
int y=to[i];
sz[x]+=sz[y];
if (sz[y]&1){
++len;
b[len]=f[y];
}
else{
if (f[y]<0) f[x]+=f[y];
else sum+=f[y];
}
}
if (len)sort(b+1,b+len+1);
b[++len]=sum;
for (int i=1;i<=len;i++)
if (i&1) f[x]+=b[i];
else f[x]-=b[i];
}
int main(){
scanf("%d",&n);
for (int i=2;i<=n;i++){
int x;
scanf("%d",&x);
add(x,i);
}
dfs(1);
cout<<((n+f[1])>>1);
return 0;
}
D - Skate:并查集+图论
当 ( x , y ) (x,y) (x,y)这个点可以从 ( 1 , 1 ) (1,1) (1,1)走来时,可以知道 x x x行以及 y y y列都必须有一个停留点。
当 ( x , y ) (x,y) (x,y)是一个平面时,那么我们将 x , y x,y x,y合并。
因为有墙,所以将 1 , 1 1,1 1,1, 1 , m 1,m 1,m, n , 1 n,1 n,1, n , m n,m n,m合并,可以想到,最后答案就是集合数量减 1 1 1,因为有列有行,我们取最小值。
#include<bits/stdc++.h>
using namespace std;
int n,m,fa[2005],t1[2005],t2[2005],s1,s2;
char a[1005][1005];
int find(int x){
if (x==fa[x]) return x;
else return fa[x]=find(fa[x]);
}
void Union(int x,int y){
fa[find(x)]=find(y);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n+m;i++) fa[i]=i;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
a[i][j]=getchar();
while (a[i][j]!='#'&&a[i][j]!='.') a[i][j]=getchar();
if (a[i][j]=='#') Union(i,j+n);
}
}
Union(1,n+1);
Union(1,n+m);
Union(n,n+1);
Union(n,n+m);
for (int i=1;i<=n;i++) t1[find(i)]=1;
for (int i=n+1;i<=n+m;i++) t2[find(i)]=1;
for (int i=1;i<=n+m;i++) s1+=t1[i];
for (int i=1;i<=n+m;i++) s2+=t2[i];
cout<<min(s1,s2)-1;
}