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;
}