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

原创 2015年07月06日 20:13:25

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


Codeforces 311(div 2):E. Ann and Half-Palindrome

题目描述:           给定半回文子串的定义,现给你一个串S和一个整数K,输出S所有子串中且是半回文排名第K的子串,半回文子串按照字典序升序顺序。(len(S) 分析:    ...

Codeforces Round #311 (Div. 2) A~E && DE题解

A Ilya and Diplomas Problem Description:Soon a school Olympiad in Informatics will be held in Ber...

Codeforces Round #311 (Div. 2) C. Arthur and Table

C. Arthur and Table time limit per test 1 second memory limit per test 256 megabytes input standa...

Codeforces Round #311 (Div. 2) —— C

C. Arthur and Table time limit per test 1 second memory limit per test 256 megabytes input sta...

Codeforces Round #311 (Div. 2) C(技巧) *D(二分图染色)

C. Arthur and Table http://codeforces.com/contest/557/problem/C 题意:一张桌子有n条桌腿,每条桌腿有相应的长度和移动花费值,要使桌子平...

Codeforces Round #283(Div.2) A,B,C,D,E 解题报告

Codeforces Round #283(Div.2) A,B,C,D,E 解题报告 codeforces 上写的题解 by Endagorion: http://codeforces.com/...

Codeforces Round #294 (Div. 2) (C D E)

C A and B and Team Training         给出大神和菜鸟的人数,必须1:2或者2:1组队,问最多组几队。如果n的2倍小于等于m,答案就是n,反过来也一样。否则答案是它们...

Codeforces Round #280 (Div. 2) 解题报告(A B C D E)

A. Vanya and Cubes         思路:累加计算叠到每个高度至少需要多少方块,然后找最后一个满足的即可。 #include #include #include #i...

Codeforces Round #319 (Div. 2)(A,B,C,E)

Codeforces Round #319 (Div. 2)A.Multiplication Table题意: 求m在n*n的加法表中出现了几次 思路:枚举1到n,累计能整除m的情况。代码:/* ...

Codeforces Round #279 (Div. 2) 解题报告 A.B.C.D.E

A - Team Olympiad 贪心水题。。都从第一个开始取即可。 代码如下: #include #include #include #include #include #include...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【Codeforces#311】 div.2 C--E
举报原因:
原因补充:

(最多只允许输入30个字)