AtCoder Regular Contest 112 Summary
A - B = C:统计+数学
考虑固定CCC,即A=B+CA=B+CA=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=LR−LR−i−L+1\sum_{i=L}^{R-L}{R-i-L+1}∑i=LR−LR−i−L+1。
化简一下:
∑i=LR−LR−i−L+1=(R−L+1)(R−2L+1)−∑i=LR−Li=(R−L+1)(R−2L+1)−(R−L+L)(R−2L+1)2=(R−L+1)(R−2L+1)−R(R−2L+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<LR-L<LR−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:动态规划+树+贪心
设fxf_xfx表示以xxx为根的子树先手与后手的金币差,szxsz_xszx表示子树大小。
我们可以递归解决问题。
设y∈sonxy\in son_xy∈sonx,分三种情况:
- fy<0,szy≡0(mod 2)f_y<0,sz_y\equiv0(\mod 2)fy<0,szy≡0(mod2),这样后手会将所有这样的结点都选一遍。
- fy≥0,szy≡0(mod 2)f_y\ge 0,sz_y\equiv0(\mod2)fy≥0,szy≡0(mod2),这样后手要避免选择yyy。
- szy≡1(mod 2)sz_y\equiv1(\mod 2)szy≡1(mod2),这样的话后手每次都要选择较小的fyf_yfy。
这样的话,我们每一次把这些fff存起来排序,就用O(nlog2n)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)走来时,可以知道xxx行以及yyy列都必须有一个停留点。
当(x,y)(x,y)(x,y)是一个平面时,那么我们将x,yx,yx,y合并。
因为有墙,所以将1,11,11,1,1,m1,m1,m,n,1n,1n,1,n,mn,mn,m合并,可以想到,最后答案就是集合数量减111,因为有列有行,我们取最小值。
#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;
}