关闭

【Codeforces#311】 div.2 C--E

标签: codeforces
217人阅读 评论(0) 收藏 举报
分类:

C:

题意:一张桌子有n条腿,每条腿都有锯掉所要消耗的能量。一张桌子如果最长的腿超过一半,则称稳定的。问使桌子稳定的最小需要能量。

枚举最长的腿的长度,然后用set维护一下就好了。

#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
struct elem{
    int l,d;
    void add(){
        scanf("%d%d",&l,&d);
    }
    bool operator < (const elem &a)const{
        if(l != a.l) return l < a.l;
        return d < a.d;
    }
}ss[N];
int sum[N];
multiset<int> st;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++) scanf("%d",&ss[i].l);
    for(int i = 1 ; i <= n ; i ++) scanf("%d",&ss[i].d);
    sort(ss + 1,ss + n + 1);
    sum[n + 1] = 0;
    for(int i = n ; i >= 1 ; i --) sum[i] = sum[i + 1] + ss[i].d;
    int last = 1,res = sum[1];
    st.clear();
    for(int i = 1 ; i <= n ; i ++){
        int tres = 0,cnt = 1;
        while(i < n  && ss[i].l == ss[i + 1].l){
            tres += ss[i].d;
            cnt ++;
            i ++;
        }
        tres += ss[i].d;
        while(ss[last].l < ss[i].l){
            st.insert(ss[last].d);
            last ++;
        }
        int lim = min(cnt - 1,(int)st.size());
        auto It = st.end();
        for(int j = 0 ; j < lim ; j ++){
            It --;
            tres += (*It);
        }
        res = min(res,sum[1] - tres);
    }
    printf("%d\n",res);
    return 0;
}

D:

题意:给你一个简单图,问添加多少条边可以产生奇环,并输出方案数。

分析:我们可以对图的度进行分类讨论。不妨设图中点最大度为x。

x = 0时,没有边,故最少要添加三条边,方案数为C(N,3)。

x = 1时,即任意一点最多只有一条边,因此最少添加两条边可以构成一个环。方案数为m*(n - 2)

x >= 2时,对于任意一个连通块,肯定可以分成一个二分图(否则就出现了奇数环)。那么可以统计二分图中两块的个数,然后任意在两块中连一条边即可得到奇数环。

#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
typedef long long LL;
struct edge{
    int to,next;
}e[N << 1];
int in[N],clo[N];
int head[N],sz;
bool flag,vis[N];
void init(){
    memset(head,-1,sizeof(head));
    memset(clo,0,sizeof(clo));
    memset(vis,0,sizeof(vis));
    sz = 0;
    flag = 1;
}
void addedge(int u,int v){
    e[sz].to = v;
    e[sz].next = head[u];
    head[u] = sz ++;
}
void dfs1(int u){
    for(int i = head[u] ; i != -1 ; i = e[i].next){
        int v = e[i].to;
        if(clo[v] == clo[u]) flag = 0;
        if(!flag) return;
        if(clo[v]) continue;
        clo[v] = -clo[u];
        dfs1(v);
    }
}
void dfs2(int u,int &t1,int &t2){
    t1 ++;
    vis[u] = 1;
    for(int i = head[u] ; i != -1 ; i = e[i].next){
        int v = e[i].to;
        if(vis[v]) continue;
        dfs2(v,t2,t1);
    }
}
int main()
{
    init();
    int n,m,u,v;
    scanf("%d%d",&n,&m);
    for(int i = 0 ; i < m ; i ++){
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
        in[u] ++;in[v] ++;
    }
    int Max = -1;
    for(int i = 1 ; i <= n && flag ; i ++)
        Max = max(Max,in[i]);
    if(Max == 0) printf("3 %I64d\n",1ll * n * (n - 1) * (n - 2) / 6);
    else if(Max == 1) printf("2 %I64d\n",1ll * m * (n - 2));
    else{
        for(int i = 1 ; i <= n ; i ++)
            if(!clo[i]){
                clo[i] = 1;
                dfs1(i);
            }
        if(flag == 0){
            printf("0 1\n");
            return 0;
        }
        LL res = 0;
        int t1,t2;
        for(int i = 1 ; i <= n ; i ++){
            if(!vis[i]){
                t1 = t2 = 0;
                dfs2(i,t1,t2);
                res += 1ll * t1 * (t1 - 1) / 2 + 1ll * t2 * (t2 - 1) / 2;
            }
        }
        printf("1 %I64d\n",res);
    }
    return 0;
}

E:

题意:定义了一种半回文串,求字典序第k大的半回文子串。

分析:首先可以通过n^2的DP求出所有子串是不是回文子串。然后可以通过求出后缀数组然后按照顺序遍历回文子串就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N = 5005;
int dp[N][N];
char s[N << 1];
int t[N],t2[N],sa[N];
int cnt[N],rank[N],c[300];
void build_sa(int n,int m){
    int *x = t,*y = t2;
    for(int i = 0 ; i < m ; i ++) c[i] = 0;
    for(int i = 0 ; i < n ; i ++) c[ x[i] = s[i] ] ++;
    for(int i = 1 ; i < m ; i ++) c[i] += c[i - 1];
    for(int i = n - 1 ; i >= 0 ; i --) sa[ --c[ x[i] ] ] = i;
    for(int k = 1 ; k <= n ; k <<= 1){
        int p = 0;
        for(int i = n - k ; i < n ; i ++) y[p ++] = i;
        for(int i = 0 ; i < n ; i ++) if(sa[i] >= k) y[p ++] = sa[i] - k;

        for(int i = 0 ; i < m ; i ++) c[i] = 0;
        for(int i = 0 ; i < n ; i ++) c[ x[i] ] ++;
        for(int i = 1 ; i < m ; i ++) c[i] += c[i - 1];
        for(int i = n - 1 ; i >= 0 ; i --) sa[ --c[ x[ y[i] ] ] ] = y[i];

        swap(x,y);
        p = 1;x[ sa[0] ] = 0;
        for(int i = 1 ; i < n ; i ++)
            x[ sa[i] ] = y[ sa[i] ] == y[ sa[i - 1] ] && y[ sa[i] + k ] == y[ sa[i - 1] + k ] ? p - 1:p ++;
        if(p >= n) break;
        m = p;
    }
}
int sum[N],flag;
char get(int i,int p){
    return s[ sa[i] + p ];
}
void solve(int l,int r,int p,int &k){
    if(l > r || k <= 0) return;
    for(int i = l ; i <= r ; i ++){
        if(flag) return;
        int j = i;
        while(k && j <= r && get(j,p) == get(i,p)){
            if(dp[ sa[j] + 1 ][ sa[j] + p + 1]) k --;
            j ++;
        }
        if(k == 0){
            for(int l = sa[j - 1] ; l <= sa[j - 1] + p ; l ++) printf("%c",s[l]);
            printf("\n");
            flag = 1;
            return;
        }
        int tl = i;
        while(tl <= j - 1 && get(tl,p + 1) == '\0') tl ++;
        solve(tl,j - 1,p + 1,k);
        i = j - 1;
    }
}
int main()
{
    int k,n;
    flag = 0;
    memset(s,'\0',sizeof(s));
    scanf("%s%d",s,&k);
    n = strlen(s);
    for(int l = 1 ; l <= n ; l ++)
    for(int i = 1 ; i + l - 1 <= n ; i ++){
        int j = i + l - 1;
        dp[i][j] = s[i - 1] == s[j - 1] && ((i + 2 > j - 2) || dp[i + 2][j - 2]);
    }
//    for(int i = 1 ; i <= n ; i ++){
//        for(int j = 1 ; j <= n ; j ++) printf("%d ",dp[i][j]);
//        printf("\n");
//    }
    s[n] = 0;
    build_sa(n + 1,128);
    solve(1,n,0,k);
    return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:28152次
    • 积分:991
    • 等级:
    • 排名:千里之外
    • 原创:73篇
    • 转载:0篇
    • 译文:0篇
    • 评论:20条
    最新评论