CF1178比赛题解

A题
小学抽屉问题,
答案就是\(max(n - s,n - t) + 1\)
复杂度\(O(T)\)
代码:

#include 

int T, n, m, i, j, k;
int a[2];

int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d %d %d",&n,&a[0],&a[1]);
        printf("%d\n",std::max(n - a[0],n - a[1]) + 1);  
    }
}

B题
我们维护一个\(vector\)数组\(v\),其中\(v_i\)存的是字母\(i\)所出现的位置。
那么因为我们是依次\(\text{push_back}\)的,
那么第\(i\)个字母的位置其实就是\(v_{i - 1}\)(因为下标从0开始)。
我们查的时候只需要将\(t_i\)遍历一遍然后取个\(max\)就好。
而访问一个下标又是\(O(1)\)的操作,
所以总复杂度为\(O(m * max(|t_i|)\)
代码:

#include  

const int maxn = 2e5 + 10;
const int maxm = 5e4 + 10;

inline void cmax(int& x,int y) {
    if(x < y)
        x = y;
}

char s[maxn];
int n, m, i, j, k; 
int cnt[27];
std::vector v[27];

int main() {
    int n;  scanf("%d",&n);  
    scanf("%s",s + 1);
    int l = strlen(s + 1);
    for(int i = 1;i <= l;i++) {
        int c = s[i] - 'a' + 1;
        v[c].push_back(i);
    }    
    scanf("%d",&m);
    while(m--) {
        static char t[maxn];  
        scanf("%s",t + 1);
        int l = strlen(t + 1);  
        memset(cnt,0,sizeof(cnt));
        for(int i = 1;i <= l;i++) 
            cnt[ t[i] - 'a' + 1 ]++;
        int ans = 0;
        for(int i = 1;i <= l;i++) {
            int c = t[i] - 'a' + 1;
            cmax(ans,v[c][ cnt[c] - 1 ]);       
        }
        printf("%d\n",ans);
    }
    return 0;
} 

C题
我们把所有操作全部分离,
然后排个序。
然后先处理不下降的,
赋值的时候如果左端点没有赋值过那就去\(n - x\)(一定保证小于左边一个),
否则就使用上一次的赋值(排过序,所以一定不降)。
剩下的如果有空隙那就表示一定是下降序列,
那么直接填就好。
于是这道题就做完了。
复杂度\(O(n)\)

#include 

const int maxn = 1010;
const int maxm = 1010;
const int inf = 0x3f3f3f3f;

template inline void read(Tp& res) {
    res = 0;  char ch = getchar();  bool neg = 0;
    while(!isdigit(ch))
        neg |= ch == '-', ch = getchar();
    while(isdigit(ch))
        res = (res << 1) + (res << 3) + (ch & 15), ch = getchar();
    if(neg)
        res = -res; 
}
inline void cmin(int& x,int y) {
    if(x > y)
        x = y;
}
inline int _abs(int x) {
    return x < 0 ? -x : x;
}

int n, m, i, j, k;  
int a[maxn];  
std::vector > q1, q2;

int main() {
    read(n);  read(m);
    for(int i = 1, op, l, r;i <= m;i++) {
        read(op);  read(l);  read(r);
        if(op)
            q1.push_back(std::make_pair(l,r));
        else
            q2.push_back(std::make_pair(l,r));
    }
    std::sort(q1.begin(),q1.end());
    std::sort(q2.begin(),q2.end());     
    int v;
    for(auto i : q1) {
        int l = i.first, r = i.second;
        if(!a[l])
            v = n - l;
        for(int j = l;j <= r;j++)
            a[j] = v;    
    }
    for(int i = 1;i <= n;i++)
        if(!a[i])
            a[i] = n - i;
    for(auto i : q2) {
        int l = i.first, r = i.second, tmp = a[l];  
        bool ok = 0;
        for(int j = l;j <= r;j++)
            if(a[j] < tmp) {
                ok = 1;
                break;
            }
        if(!ok)
            return puts("NO"), 0;    
    }        
    puts("YES");
    for(int i = 1;i <= n;i++)
        printf("%d ",a[i] + 5010);
    return 0;   
}

D题
又是一道典型的恶意评分。
我们思考一下冒泡排序的原理,每次只对两个数进行操作可以有同样的效果。
这时可以发现一点,对于一个\(a_i\),它一定要比前面的都小才可能到达指定的位置上去。
那么我们用线段树维护一下最小值就结束了...
结束了?对,结束了...
复杂度\(O(n log n)\)
代码:

#include 

const int maxn = 3e5 + 10;
const int inf = 0x3f3f3f3f;

template inline void read(Tp& res) {
    res = 0;  char ch = getchar();  bool neg = 0;
    while(!isdigit(ch))
        neg |= ch == '-', ch = getchar();
    while(isdigit(ch)) 
        res = (res << 1) + (res << 3) + (ch & 15), ch = getchar();
    if(neg)
        res = -res; 
}
inline int _min(int a,int b) { return a < b ? a : b; }
inline void cmin(int& a,int b) {
    if(a > b)
        a = b;
}
inline void cmax(int& a,int b) {
    if(a < b)
        a = b;  
}

int n, m, i, j, k, T, mx;  
int a[maxn], b[maxn], c[maxn], pos[maxn], t[maxn << 2];
std::queue q[maxn];  

inline bool check() {
    for(int i = 1;i <= mx;i++)
        if(c[i] != 0)
            return 0;
    return 1;    
}

inline void push_up(int u) {
    t[u] = _min(t[u << 1],t[u << 1 | 1]);
}
void build(int l,int r,int u) {
    if(l == r) 
        return t[u] = a[l], void(); 
    int mid = (l + r) >> 1;
    build(l,mid,u << 1);
    build(mid + 1,r,u << 1 | 1);
    push_up(u);  
}
int query(int ql,int qr,int l,int r,int u) {
    if(ql <= l && r <= qr) 
        return t[u];
    int mid = (l + r) >> 1, res = inf;
    if(ql <= mid)
        cmin(res,query(ql,qr,l,mid,u << 1));
    if(mid < qr)
        cmin(res,query(ql,qr,mid + 1,r,u << 1 | 1));
    return res;  
}
void modify(int m,int l,int r,int u,int v) {
    if(l == m && r == m)
        return t[u] = v, void();
    int mid = (l + r) >> 1;
    if(m <= mid)
        modify(m,l,mid,u << 1,v);
    else
        modify(m,mid + 1,r,u << 1 | 1,v);
    push_up(u);        
}

int main() {
    read(T);
    while(T--) {
        read(n);  mx = 0;
        for(int i = 1;i <= n;i++)
            c[i] = 0;  
        for(int i = 1;i <= n;i++) {
            read(a[i]);
            cmax(mx,a[i]);
            c[ a[i] ]++;
        }
        for(int i = 1;i <= n;i++)
            read(b[i]), cmax(mx,b[i]), c[ b[i] ]--;     
        if(!check()) {
            puts("NO");
            continue; 
        } 
        for(int i = 1;i <= n;i++)
            q[ a[i] ].push(i);  
        for(int i = 1;i <= n;i++) {
            pos[i] = q[ b[i] ].front();
            q[ b[i] ].pop();
        } 
        build(1,n,1);  bool flag = 1;
        for(int i = 1;i <= n;i++) {
            int p = pos[i];  
            if(query(1,p,1,n,1) != b[i]) {  
                flag = 0;  
                puts("NO");   
                break;
            }
            modify(p,1,n,1,inf);
        }
        if(flag)
            puts("YES");
    }
    return 0;
}

E题
树形dp。
设u为当前节点,
\(f[fa_u] = S_{fa_u} + sz_{u} + n + S_{ch_u}\)
\(f[u] = S_{ch_u} + 2 * n - sz_u + S_{fa_u}\)
可以推出\(f[u] = f[fa_u] + n - sz_u * 2\)
转移即可,

#include 

typedef long long ll;
const int maxn = 2e5 + 10;  

int cnte, n, m, i, j, k;
int sz[maxn], hd[maxn], ver[maxn << 1], nxt[maxn << 1];
ll f[maxn], ans;     

inline void adde(int u,int v) {
    ver[++cnte] = v;  nxt[cnte] = hd[u];
    hd[u] = cnte;  return;   
}
inline void cmax(ll& a,ll b) {
    if(a < b)
        a = b;
}

void dfs1(int u,int pa) {
    sz[u] = 1;
    for(int i = hd[u];~i;i = nxt[i]) {
        int v = ver[i];
        if(v == pa)
            continue;
        dfs1(v,u);  
        sz[u] += sz[v];
    }
    f[1] += sz[u];
}

void dfs2(int u,int pa) {
    for(int i = hd[u];~i;i = nxt[i]) {
        int v = ver[i];
        if(v == pa)
            continue;
        f[v] = f[u] + n - 2 * sz[v];
        cmax(ans,f[v]);
        dfs2(v,u);   
    }
}

int main() {
    memset(hd,-1,sizeof(hd));
    scanf("%d",&n);
    for(int i = 1, u, v;i < n;i++) {
        scanf("%d %d",&u,&v);
        adde(u,v);
        adde(v,u);
    }
    dfs1(1,0);
    dfs2(1,0);   
    printf("%lld\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/Sai0511/p/11173529.html

你可能感兴趣的:(CF1178比赛题解)