1001 Oracle
先记录 0−90-90−9这101010个数字分别有多少个。不难看出,最小的一个存在的数字和其余的数字降序排列的相加就是答案,但是最小的那个数字不能是000,因为题面上说明是正整数。将这两个数加起来时,注意处理进位问题。考虑无解的情况,即一串数字中仅存在111个非000数字或不存在。(PS.这道题目原本的时限是1s1s1s,考虑到题目的难度和评测机的问题,开了4s4s4s,大家可以自己在FST以后看一下时间。如果是时限是1s1s1s的话,sortsortsort是过不了的,输出也需要优化一下)
时间复杂度 O(Tn)O(Tn)O(Tn)。
1002 Arrange
首先,根据题意可得B数组应是单调不升的,C数组是单调不降的。
可以发现A1=B1=C1 A_1 = B_1 = C_1 A1=B1=C1,所以如果B1≠C1 B_1 \neq C_1 B1≠C1无解。
进一步,我们发现如果Bi<Bi−1 B_i < B_{i-1} Bi<Bi−1,Ai=Bi A_i = B_i Ai=Bi;如果Ci>Ci−1 C_i > C_{i-1} Ci>Ci−1,Ai=Ci A_i = C_i Ai=Ci。但是如果Bi<Bi−1 B_i < B_{i-1} Bi<Bi−1和Ci>Ci−1 C_i > C_{i-1} Ci>Ci−1同时满足,就会产生冲突导致无解。
考虑Bi=Bi−1 B_i = B_{i-1} Bi=Bi−1和Ci=Ci−1 C_i = C_{i-1} Ci=Ci−1同时满足的情况,此时应有Ai∈(Bi,Ci) A_i \in (B_i,C_i) Ai∈(Bi,Ci)且Ai A_i Ai没有在之前使用过。因为(Bi,Ci) (B_i,C_i) (Bi,Ci)是不断变大的,我们只需维护一下这个区间内有多少值已经被使用过了,用乘法原理统计答案即可。注意到如果某时刻Ai A_i Ai没有值可以使用,也会导致无解。
时间复杂度O(Tn) O(Tn) O(Tn)。
1003 Wool
考虑三角形三条边a,b,c a,b,c a,b,c (a≥b) (a \ge b) (a≥b)的关系a−b<c,a+b>c a - b < c, a + b > c a−b<c,a+b>c,即c∈(a−b,a+b) c \in (a-b,a+b) c∈(a−b,a+b)。
令加入的边为c c c,枚举所有边作为a a a的情况。对于所有可行的b b b,显然与a a a相差最小的可以让(a−b,a+b) (a-b,a+b) (a−b,a+b)覆盖范围最大,所以可以贪心地选择不大于a a a的最大的b b b。
于是我们可以先将边按长度排序,然后ai a_i ai和ai+1 a_{i + 1} ai+1建一条线段。线段并是不合法的部分。
将所有线段按左端点排序,按序扫描一遍,过程中统计答案即可。
时间复杂度O(Tn logn) O(Tn\ \log n) O(Tn logn)。
1004 Palace
先不考虑删点。平面上n n n个点求最近点对是一个经典问题。
对所有点按照x x x坐标排序。然后分治,求出左半边和右半边的最近点对,对于两边的最近距离取较小的,记为d d d。取从分治的中间点向左右各距离为d d d的范围中的所有点,把这些点按照y y y坐标排序。对于每个点,扫一下与它y y y坐标差小于等于d d d的点,更新答案,可以证明这样的点是很少的,不超过6个。时间复杂度O(Tn log2n) O(Tn\ \log ^ 2 n) O(Tn log2n)。
考虑删点的情况:
⋅\cdot ⋅ 删去的点不属于最近点对,对于答案没有影响。
⋅\cdot ⋅ 平面上存在两对没有公共点的最近点对,则删去的点至多属于一对最近点对,对于答案没有影响。
⋅\cdot ⋅ 平面上所有最近点对有公共点,且删去的点是某个公共点,最近点对会发生变化。
只有第三种情况,删点会对答案造成影响。而只要求出最近点对,那个对答案造成影响的点一定在最近点对上。
所以只需要先对于所有点求出最近点对。然后分别删去其中的两个点,各求一遍最近点对。删去那两个点后的贡献单独计算,其余情况只需要计算全局最近点对的贡献即可。
时间复杂度O(Tn log2 n) O(Tn\ \log ^ 2\ n) O(Tn log2 n)。如果把y y y轴排序改为归并,可以做到O(Tnlogn) O(Tn \log n) O(Tnlogn)的时间复杂度。
EXTEXTEXT 删去两个点怎么做?
1005 Jewelry
枚举区间右端点r r r,考虑l l l的可行域的大小。
注意到每个字符的贡献一定是一段区间,所以l l l的可行域是若干段区间的并。
每次右端点向右移时,至多会有一个字符的区间发生改变。
所以我们需要一个支持插入一条线段,删除一条线段和查询线段并操作的数据结构。
和扫描线类似,我们可以用经典的线段树来维护。
时间复杂度O(Tn logn) O(Tn\ \log n) O(Tn logn)。
1001:
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
using namespace std;
typedef long long LL;
const int maxn = 10000005;
char s[maxn];
int cnt[20];
void work()
{
memset(cnt, 0, sizeof cnt);
scanf("%s", s);
for(int i = 0; s[i]; i++) cnt[s[i] - '0']++;
int flag = 0;
for(int i = 1; i < 10; i++) flag += cnt[i];
if(flag <= 1) {
printf("Uncertain\n");
return;
}
for(int i = 1; i < 10; i++) if(cnt[i]) {
cnt[i]--, flag = i;
break;
}
int tcnt = 0;
for(int i = 0; i < 10; i++) tcnt += cnt[i];
for(int i = 1, j = 9; i <= tcnt; i++) {
while(cnt[j] == 0) j--;
cnt[j]--;
s[i] = j;
}
s[0] = 0;
for(int i = tcnt; i >= 0; i--) {
s[i] += flag;
if(s[i] >= 10) s[i] -= 10, flag = 1;
else flag = 0;
}
if(s[0]) {
for(int i = 0; i <= tcnt; i++) printf("%d", s[i]);
}
else {
for(int i = 1; i <= tcnt; i++) printf("%d", s[i]);
}
printf("\n");
}
int main()
{
int _;
scanf("%d", &_);
while(_--) {
work();
}
return 0;
}
1002
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
using namespace std;
typedef long long LL;
const int maxn = 100005;
int b[maxn], c[maxn];
int vis[maxn];
void work()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
for(int i = 1; i <= n; i++) scanf("%d", &c[i]);
for(int i = 2; i <= n; i++) {
if(b[i] > b[i-1] || c[i] < c[i-1]) {
printf("0\n");
return;
}
}
if(b[1] != c[1]) {
printf("0\n");
return;
}
memset(vis, 0, sizeof vis);
vis[b[1]] = vis[c[1]] = 1;
LL ans = 1, cnt;
for(int i = 2; i <= n; i++) {
if(vis[b[i]] && vis[c[i]]) {
ans = ans * (c[i] - b[i] - i + 2) % 998244353;
}
if(!vis[b[i]] && !vis[c[i]]) ans = 0;
vis[b[i]] = vis[c[i]] = 1;
}
printf("%lld\n", ans);
}
int main()
{
int _;
scanf("%d", &_);
while(_--) {
work();
}
return 0;
}
1003
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
using namespace std;
typedef long long LL;
const int maxn = 100005;
LL a[maxn];
void work()
{
int n;
LL L, R;
scanf("%d%lld%lld", &n, &L, &R);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
sort(a+1, a+n+1);
LL ans = 0;
for(int i = n; i >= 2; i--) {
if(R < L) break;
LL mx = a[i] + a[i-1] - 1;
LL mi = a[i] - a[i-1] + 1;
if(R > mx) ans += R - max(mx, L-1);
R = min(R, mi-1);
}
if(R > L) ans += R - L + 1;
printf("%lld\n", ans);
}
int main()
{
int _;
scanf("%d", &_);
while(_--) {
work();
}
return 0;
}
1004
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double INF = 1e20;
const int N = 100005;
typedef long long LL;
struct Point
{
int id;
double x;
double y;
}point[N], po[N];
int n, tt1, tt2;
int tmpt[N];
struct node
{
double d;
int id1, id2;
node(double d = 0, int id1 = 0, int id2 = 0) : d(d), id1(id1), id2(id2) {}
bool operator < (const node &b) const {
return d < b.d;
}
bool operator > (const node &b) const {
return d > b.d;
}
};
bool cmpxy(const Point& a, const Point& b)
{
if(a.x != b.x)
return a.x < b.x;
return a.y < b.y;
}
bool cmpy(const int& a, const int& b)
{
return point[a].y < point[b].y;
}
node dis(int i, int j)
{
return node(sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)
+ (point[i].y-point[j].y)*(point[i].y-point[j].y)), i, j);
}
node Closest_Pair(int left, int right)
{
node d = node(INF, left, right);
if(left==right)
return d;
if(left + 1 == right)
return dis(left, right);
int mid = (left+right)>>1;
node d1 = Closest_Pair(left,mid);
node d2 = Closest_Pair(mid+1,right);
d = min(d1,d2);
int i,j,k=0;
//分离出宽度为d的区间
for(i = left; i <= right; i++)
{
if(fabs(point[mid].x-point[i].x) <= d.d)
tmpt[k++] = i;
}
sort(tmpt,tmpt+k,cmpy);
//线性扫描
for(i = 0; i < k; i++)
{
for(j = i+1; j < k && point[tmpt[j]].y-point[tmpt[i]].y<d.d; j++)// 理解!!
{
node d3 = dis(tmpt[i],tmpt[j]);
if(d > d3)
d = d3;
}
}
return d;
}
LL solve()
{
sort(point,point+n,cmpxy);
node tt = Closest_Pair(0,n-1);
double t = (tt.d);
tt1 = point[tt.id1].id;
tt2 = point[tt.id2].id;
//printf("OOOO %d %d\n", tt1, tt2);
return (LL)(t * t + 0.5);
}
void work()
{
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%lf%lf", &po[i].x, &po[i].y), po[i].id = i;
for(int i = 0; i < n; i++) point[i] = po[i];
LL ans = solve() * (n-2);
int t1 = tt1, t2 = tt2;
//printf("%d %d\n", t1, t2);
n = n-1;
int cnt = 0;
for(int i = 0; i < n + 1; i++) if(po[i].id != t1) {
point[cnt++] = po[i];
}
ans += solve();
cnt = 0;
for(int i = 0; i < n + 1; i++) if(po[i].id != t2) {
point[cnt++] = po[i];
}
ans += solve();
printf("%lld\n", ans);
}
int main()
{
int _;
scanf("%d", &_);
while(_--) work();
return 0;
}