A - Election 2
高桥日常出镜,kkk 好好学学。
点击查看代码
#include<cstdio>
using namespace std;int main()
{int n,t,a;scanf("%d%d%d",&n,&t,&a);if(t>n-t||a>n-a) printf("Yes\n");else printf("No\n");return 0;
}
B - Vertical Writing
某人被这道题卡了,默哀一秒钟。
内层循环要倒着遍历,小小地坑了我一下。
点击查看代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;const int N=105;
int n;
char str[N][N];int main()
{scanf("%d",&n);int h=0;for(int i=1;i<=n;i++){scanf("%s",str[i]+1);h=max(h,(int)strlen(str[i]+1));}for(int i=1;i<=h;i++){int cnt=0;for(int j=n;j>=1;j--){if(str[j][i]){for(int k=1;k<=cnt;k++)putchar('*');cnt=0;putchar(str[j][i]);}else cnt++;}putchar('\n');}return 0;
}
C - Balls and Bag Query
原来 multiset
的 size()
返回的是元素个数(重复的算多个)。
模拟就好啦,加减的时候判断是不是少了或多了一种元素。
点击查看代码
#include<cstdio>
#include<set>
using namespace std;const int X=1e6+5;
int q,cnt[X];int main()
{scanf("%d",&q);int ans=0;for(int i=1;i<=q;i++){int op; scanf("%d",&op);if(op==1){int x; scanf("%d",&x);if(!(cnt[x]++)) ans++;}if(op==2){int x; scanf("%d",&x);if(!(--cnt[x])) ans--;}if(op==3){printf("%d\n",ans);}}return 0;
}
D - Cuboid Sum Query
好家伙,三维前缀和(题目名称说的很形象,就是长方体总和)。
没咋推,就跟着容斥原理的加减交替的形式,胡写一通就成了。
点击查看代码
#include<cstdio>
using namespace std;const int N=105;
int n,a[N][N][N],sum[N][N][N],q;int main()
{scanf("%d",&n);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=1;k<=n;k++){scanf("%d",&a[i][j][k]);sum[i][j][k] = a[i][j][k]+sum[i-1][j][k]+sum[i][j-1][k]+sum[i][j][k-1]-sum[i][j-1][k-1]-sum[i-1][j][k-1]-sum[i-1][j-1][k]+sum[i-1][j-1][k-1];}scanf("%d",&q);for(int i=1;i<=q;i++){int x1,y1,z1,x2,y2,z2;scanf("%d%d%d%d%d%d",&x1,&x2,&y1,&y2,&z1,&z2);printf("%d\n",sum[x2][y2][z2]-sum[x1-1][y2][z2]-sum[x2][y1-1][z2]-sum[x2][y2][z1-1]+sum[x2][y1-1][z1-1]+sum[x1-1][y2][z1-1]+sum[x1-1][y1-1][z2]-sum[x1-1][y1-1][z1-1]);}return 0;
}
E - Manhattan Multifocal Ellipse
赛时基本都做这道题来了。
从左往右扫描所有点,每次扫描线向右移动一格,相当扫描线上每个点和左边所有点的距离都增加了 \(1\),和右边所有点的距离都缩短了 \(1\)(曼哈顿距离)。
然后我们只需要找到每次移动以后这根扫描线上总距离小于等于 \(d\) 的点就行了。
赛事乱画的草稿,可以辅助理解一下:
就是实现起来有点麻烦。
首先要把所有的坐标都转为正数,这个只需要全部加上一个常数就行了(我这里加的是 \(2\times10^6\),因为坐标系外也可能有合法的点)。
然后处理出对于某横坐标点数的前缀和,用于查找扫描线左右的点数。
接着我们需要知道对于初始位置(我这里是 \(0\))扫描线上每个位置距离所有点的曼哈顿距离和,这个有点小难度。
-
初始位置扫描线上所有位置横坐标相等,所以直接枚举所有点,横坐标相加即可。
-
纵坐标之差之和纵坐标有关,所以可以将所有点的纵坐标投影到初始位置扫描线上来。先找某位置与下面所有投影的距离和,具体来说:从下往上遍历所有位置,记录当前位置以下的投影数,在遍历的过程中每上移一格,总距离增加的就是这个点数。随后再找与上面所有投影的距离和,两者相加就可以得到纵坐标距离和。
-
横坐标距离和加纵坐标距离和就是每个位置距离所有点的曼哈顿距离和。
最后,从左往右推扫描线。因为每次对线上距离的修改都是全局同加同减同查,所以只需要维护它变化的值。又因为全局加减不改变内部大小关系,所以可以事先排序。接着就可以二分查找扫描线上距离加变化之小于等于 \(d\) 的点的数量了,直接用 upper_bound
来查找也行。
#include<cstdio>
#include<algorithm>
using namespace std;const int N=2e5+5,D=2e6;
#define D ((D<<1)+5)
int n,x[N],y[N];
int d,a[D];
int sumcnt[D];
long long ldis[D],rdis[D],dis[D];
int ycnt[D];
#undef Dinline int getsum(int l,int r)
{if(!l) return sumcnt[r];return sumcnt[r]-sumcnt[l-1];
}
int main()
{scanf("%d%d",&n,&d);for(int i=1;i<=n;i++){scanf("%d%d",&x[i],&y[i]);x[i]+=D,y[i]+=D;a[x[i]]=y[i];sumcnt[x[i]]++;}for(int i=0;i<=D<<1;i++)sumcnt[i]+=sumcnt[i-1];long long xdis=0;for(int i=1;i<=n;i++){xdis+=x[i];ycnt[y[i]]++;}long long lytot=0;for(int i=0;i<=D<<1;i++){ldis[i]=(i?ldis[i-1]:0)+lytot;lytot+=ycnt[i];}long long rytot=0;for(int i=D<<1;i>=0;i--){rdis[i]=rdis[i+1]+rytot;rytot+=ycnt[i];}for(int i=0;i<=D<<1;i++){dis[i]=ldis[i]+rdis[i]+xdis;}sort(dis,dis+(D<<1)+1);long long ans=0,delta=0;for(int i=0;i<=D<<1;i++){ans+=upper_bound(dis,dis+(D<<1)+1,d-delta)-dis;delta+=getsum(0,i);delta-=getsum(i+1,D<<1);}printf("%lld\n",ans);return 0;
}