A

做法一:答案一定是相邻两个的差的最小值。

考虑反证法:如果 $[l,r](l+1 < r)$ 是答案,那么中间一定能取到一段小于等于平均数的。

做法二:二分答案。

首先答案是 $\min_{i,j} \frac{a_i-a_j}{j-i}$,考虑二分最小值,那么相当于对于所有 $j>i$ 要有 $a_i-a_j \geq kj-ki$,也就是 $a_i+k_i \geq a_j+k_j$,判断是否不增就行。

#include <bits/stdc++.h>

#define fi first
#define se second
#define db double
#define U unsigned
#define P std::pair<int,int>
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(int i = a;i <= b;++i)
#define ROF(i,a,b) for(int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

const int MAXN = 1e5 + 5;
int n;
LL a[MAXN];

inline bool chk(LL k){
    FOR(i,2,n){
        if(a[i-1]+k*(i-1) < a[i]+k*i) return 0;
    }
    return 1;
}

int main(){
    scanf("%d",&n);FOR(i,1,n) scanf("%lld",a+i);
    LL l = 0,r = 2e9,ans = -1;
    while(l <= r){
        LL mid = (l + r) >> 1;
        if(chk(mid)) ans = mid,l = mid+1;
        else r = mid-1;
    }
    printf("%lld\n",ans);
    return 0;
}

B

意思是前 $\frac{n}{2}$ 是排名前 $\frac{n}{2}$ 小的,那么标记出来应该移动的点(本来应该在后半部分,但是最初在前半部分),从里向外配对即可。(也考虑跨过每个点的贡献,是两边点的个数的最小值)

#include <bits/stdc++.h>

#define fi first
#define se second
#define db double
#define U unsigned
#define P std::pair<int,int>
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(int i = a;i <= b;++i)
#define ROF(i,a,b) for(int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

const int MAXN = 5e5 + 5;

int a[MAXN],n;
P b[MAXN];
bool vis[MAXN];

int main(){
    scanf("%d",&n);
    FOR(i,1,n) scanf("%d",a+i),b[i] = MP(a[i],i);
    std::sort(b+1,b+n+1);
    FOR(i,1,n/2) vis[b[i].se] = 1;
    int tp = 0;FOR(i,n/2+1,n) tp += vis[i];
    LL ans = 0;
    std::vector<int> p1,p2;
    FOR(i,1,n/2) if(!vis[i]) p1.pb(i);
    FOR(i,n/2+1,n) if(vis[i]) p2.pb(i);
    FOR(i,0,tp-1) ans += p2[i]-p1[tp-i-1];
    printf("%lld\n",ans);
    return 0;
}

C

$lcp$ 问题,可以考虑建 trie 树,两个串的 $lcp$ 就是 $lca$。

然后发现我们在每一个点肯定是尽量匹配子树内的点,所以自下往上贪心即可。注意卡空间,用 map 或者 vector 优化。

#include <bits/stdc++.h>

#define fi first
#define se second
#define db double
#define U unsigned
#define P std::pair<int,int>
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(int i = a;i <= b;++i)
#define ROF(i,a,b) for(int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

const int MAXN = 2e6 + 5;
int n,k;
//std::map<int,int> ch[MAXN];
std::vector<P> ch[MAXN];
//std::vector<int> ch[MAXN];
int dep[MAXN];
char str[100000+5];
int rt = 1,tot = 1;
int sm[MAXN];

inline int find(int v,int y){
    for(auto x:ch[v]) if(x.fi == y) return x.se;
    return 0;
}

inline void insert(char str[]){
    int len = strlen(str+1),v = rt;
    FOR(i,1,len){
        int o = str[i]-'a';
        int t = find(v,o);
        if(!t) ch[v].pb(MP(o,++tot)),dep[tot] = dep[v]+1,t = tot;
        v = t;
    }
    sm[v]++;
}

LL ans = 0;

inline void dfs(int v){
    for(auto x:ch[v]){
        dfs(x.se);
        sm[v] += sm[x.se];
    }
    ans += dep[v]*(sm[v]/k);
    sm[v] %= k;
}

int main(){
//    freopen("C.in","r",stdin);
//    freopen("C.out","w",stdout);
    scanf("%d%d",&n,&k);
    FOR(i,1,n){
        scanf("%s",str+1);insert(str);
    }
    dfs(1);
    printf("%lld\n",ans);
    return 0;
}

D

比较有意思,但是数据太水了。

这种东西显然我们有一个单次询问 $O(k^2 \log n)$ 的做法:转化为 $k^2$ 次二维数点。

那么我们考虑对着根号分治一下:设 $T = \sqrt{\sum_i k_i}$,如果 $k \geq T$,这样的询问不会有超过 $T$ 个,暴力即可。

如果 $k < T$,拆成 $k^2$ 个询问,我们来分析下询问次数最大有多少个(我之前一直以为是 $k^2$ 个,才发现不是)。

那么可以使用 $O(T)-O(1)$ 的分块技巧实现单点修改,前缀查询,根号平衡后复杂度是 $O(k\sqrt k)$ 的。

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>

#define fi first
#define se second
#define db double
#define U unsigned
#define P std::pair<int,int>
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(int i = a;i <= b;++i)
#define ROF(i,a,b) for(int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

const int MAXN = 2e5 + 5;
int n,m,N,q;
int ans[MAXN];

inline char nc(){
    #define SIZE 1000000+3
    static char buf[SIZE],*p1 = buf+SIZE,*p2 = buf+SIZE;
    if(p1 == p2){
        p1 = buf;p2 = buf+fread(buf,1,SIZE,stdin);
        if(p1 == p2) return -1;
    }
    return *p1++;
    #undef SIZE
}

template <typename T>
inline void read(T &x){
    x = 0;int flag = 0;char ch = nc();
    while(!isdigit(ch)){
        if(ch == '-') flag = 1;
        ch = nc();
    }
    while(isdigit(ch)){
        x = (x<<1) + (x<<3) + (ch^'0');
        ch = nc();
    }
    if(flag) x = -x;
}

struct Node{
    int y;char opt,d;int id;// 0 = mod

    Node(int y=0,char opt=0,char d=0,int id=0) : y(y),opt(opt),d(d),id(id) {}
};
std::vector<Node> G[MAXN];

int l[MAXN],r[MAXN],B;

inline void add(int x1,int x2,int y1,int y2,int d,int id){
    if(x1 > x2 || y1 > y2) return;
    G[x2].pb(Node(y2,1,1*d,id));
    G[x2].pb(Node(y1-1,1,-1*d,id));
    G[x1-1].pb(Node(y2,1,-1*d,id));
    G[x1-1].pb(Node(y1-1,1,1*d,id));
}

const int MAXM = 500+5;

struct DS{// O(sqrt(n)) 单点修改 O(1) 查询前缀和
    int B,n;
    int bel[MAXN];
    int sm[MAXM][MAXM],pre[MAXM];

    inline void build(int xxx){
        n = xxx;B = std::sqrt(1.0*n);
        FOR(i,1,n) bel[i] = (i-1)/B+1;
    }

    inline void add(int pos,int x){
//        FOR(i,pos,n) pre[i] += x;
//        return;
        FOR(i,bel[pos]+1,bel[n]) pre[i] += x;
        FOR(i,pos-(bel[pos]-1)*B,bel[pos]*B-(bel[pos]-1)*B) sm[bel[pos]][i] += x;
    }

    inline int query(int x){
//        return pre[x];
        return pre[bel[x]]+sm[bel[x]][x-(bel[x]-1)*B];
    }
}ds;

bool vis[MAXN];
int uu[MAXN],vv[MAXN];

int main(){
//    freopen("D.in","r",stdin);
//    freopen("D.out","w",stdout);
    read(n);read(m);read(q);
    FOR(i,1,m){
        int u,v;read(u);read(v);
        if(u > v) std::swap(u,v);
        uu[i] = u;vv[i] = v;
        G[u].pb(Node(v,0));
    }
    B = 300;
    FOR(id,1,q){
        int k;read(k);
        if(k >= B){
            FOR(i,1,n) vis[i] = 0;
            FOR(i,1,k){
                int l,r;read(l);read(r);
                FOR(j,l,r) vis[j] = 1;
            }
            FOR(i,1,m) ans[id] += vis[uu[i]]&vis[vv[i]];
        }
        else{
            FOR(i,1,k) read(l[i]),read(r[i]);
 //           if(id != 6) continue;
            FOR(i,1,k){
                FOR(j,i,k){
                    add(l[i],r[i],l[j],r[j],1,id);
                }
            }
        }
    }
    ds.build(n);
    FOR(i,0,n){
        for(auto x:G[i]){
            if(x.opt == 0) ds.add(x.y,1);
        }
        for(auto x:G[i]){
            if(x.opt == 1) ans[x.id] += x.d*ds.query(x.y);
        }
    }
//    DEBUG(ans[1]);
    FOR(i,1,q) puts(ans[i]?"GG":"SAFE");
    return 0;
}
Last modification:October 5th, 2020 at 09:35 pm
如果觉得我的文章对你有用,请随意赞赏