BestCoder 2nd Anniversary

1001 Oracle


先記錄 0−90-909101010個數字分別有多少個。不難看出,最小的一個存在的數字和其餘的數字降序排列的相加就是答案,但是最小的那個數字不能是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 B1C1無解。

進一步,我們發現如果Bi<Bi−1 B_i < B_{i-1} Bi<Bi1Ai=Bi A_i = B_i Ai=Bi;如果Ci>Ci−1 C_i > C_{i-1} Ci>Ci1Ai=Ci A_i = C_i Ai=Ci。但是如果Bi<Bi−1 B_i < B_{i-1} Bi<Bi1Ci>Ci−1 C_i > C_{i-1} Ci>Ci1同時滿足,就會產生衝突導致無解。

考慮Bi=Bi−1 B_i = B_{i-1} Bi=Bi1Ci=Ci−1 C_i = C_{i-1} Ci=Ci1同時滿足的情況,此時應有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) (ab)的關係a−b<c,a+b>c a - b < c, a + b > c ab<c,a+b>c,即c∈(a−b,a+b) c \in (a-b,a+b) c(ab,a+b)

令加入的邊爲c c c,枚舉所有邊作爲a a a的情況。對於所有可行的b b b,顯然與a a a相差最小的可以讓(a−b,a+b) (a-b,a+b) (ab,a+b)覆蓋範圍最大,所以可以貪心地選擇不大於a a a的最大的b b b

於是我們可以先將邊按長度排序,然後ai a_i aiai+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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章