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

A:一个一个点向图里面加,判断其所在的位置与其他的点是否可以构成小矩形就可以了。

B:贪心,如果前面的偶数有比他小的就找到一个最靠前的交换,如果前面的偶数都比它小,就找一个最靠后的交换。

C:贪心,把蜡烛尽可能的放在恶魔,来之前,这样可以充分利用蜡烛的时间,模拟一下,不停地向前方就可以了。如果蜡烛时间小于需要的数目,一定不可以。

<span style="font-size:18px;">const int maxn = 2010;


int vis[maxn];
int num[maxn];

int main()
{
    int m, t, r;
    while(cin >>m>>t>>r)
    {
        for(int i = 1; i <= m; i++)
            scanf("%d",&num[i]);
        if(r > t)
        {
            puts("-1");
            continue;
        }
        int ans = 0;
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= m; i++)
        {
            int x = num[i]-1;
            while(vis[num[i]+1000] < r)
            {
                for(int k = x-1; k <= x+t; k++)
                    vis[k+1000]++;
                ans++;
                x --;
            }
        }
        cout<<ans<<endl;
    }
}</span>

D:欧拉路径+打印路径。

判断欧拉路径的方法是,统计出来他的度(入度+, 出度-)。如果所有的度均为0,或者只有一对度数为(+1,-1)的,那么就可以构成路径。但是这题还必须保证字符串的数目,所以判断之后,还有跑一遍dfs求出长度,判断长度是否满足条件。

打印路径的时候,先dfs再保存边,这样可以保证一开始存的边一定是距离“起点”最远的。

<span style="font-size:18px;">const int maxn = 200010;
char str[maxn][10];

int deg[maxn];
int ans[maxn];
int vis[maxn];
int cur[maxn];

vector<pair<int, int> > G[maxn*3];

int cnt;

int Get(char x)
{
    if ('0' <= x && x <= '9')return x-'0';
    if ('a' <= x && x <= 'z')return x-'a'+10;
    return x-'A'+36;
}

int get_x(int x)
{
    return Get(str[x][0])*62+Get(str[x][1]);
}

int get_y(int y)
{
    return Get(str[y][1])*62+Get(str[y][2]);
}

void dfs(int x, int y)
{
    int xp;
    int n = G[x].size();
    while(cur[x] < n)
    {
        if(!vis[G[x][xp = cur[x]++].second])
        {
            vis[G[x][xp].second] = 1;
            dfs(G[x][xp].first, G[x][xp].second);
        }
    }
    ans[cnt++] = y;
}


bool judge(int n)
{
    int x = 0;
    int y = 0;
    int pos = get_x(0);
    for(int i = 0; i < 62*62+100; i++)
    {
        if(deg[i] > 1 || deg[i] < -1) return false;
        if(deg[i] == 1)
        {
            x++;
            pos = i;
        }
        if(deg[i] == -1) y++;
    }
    if(x != y || x > 1) return false;
    dfs(pos, -1);
    cnt--;
    return cnt >= n;
}

int main()
{
    int n;
    while(cin >>n)
    {
        memset(cur, 0, sizeof(cur));
        memset(vis, 0, sizeof(vis));
        memset(deg, 0, sizeof(deg));
        cnt = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%s", str[i]);
            int x = get_x(i);
            int y = get_y(i);
            G[x].push_back(make_pair(y, i));
            deg[x]++;
            deg[y]--;
        }
        if(!judge(n))
        {
            cout<<"NO"<<endl;
            continue;
        }
        puts("YES");
        printf("%s",str[ans[cnt-1]]);
        for(int i = cnt-2; i >= 0; i--)
            printf("%s", str[ans[i]]+2);
        puts("");
    }
    return 0;
}


/*
6
abc
bca
cab
cad
adc
dca
*/</span>

E:有两种解法。一种是贪心,一种是dp。

贪心的话,就是把这个当前的括号能匹配到的范围放入栈顶,如果有的右短点位于这个区间之间就出栈。如果栈空了,还有没匹配到的就说明是不合法的。就是让近的尽可能的早点匹配出去。

贪心,解法:

const int maxn = 610;

struct node
{
    int l, r;
}f[maxn];

char str[maxn*2];

int main()
{
    int n;
    while(cin >>n)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d %d",&f[i].l, &f[i].r);
        stack<pair<int , int> > st;
        int top = 0;
        int flag = 0;
        for(int i = 1; i <= n; i++)
        {
            st.push(make_pair(f[i].l+top, f[i].r+top));
            str[top++] = '(';
            while(!st.empty() && st.top().first <= top && top <= st.top().second)
            {
                str[top++] = ')';
                st.pop();
            }
            if(!st.empty() && top > st.top().second)
            {
                flag = 1;
                break;
            }
        }
        if(flag || !st.empty())
        {
            puts("IMPOSSIBLE");
            continue;
        }
        for(int i = 0; i < top; i++) cout<<str[i];
        cout<<endl;
    }
}


dp:dp的解法就是区间dp,dp[i][]表示第i个左括号到第j个左括号已经成功匹配。我们枚举第i到j之间的右括号的位置为k,那么if(dp[i+1][k] && dp[k+1][j]) dp[i][j] = 1。1代表可以匹配额,0代表不可以匹配。

dp解法:

const int maxn = 610;

int dp[maxn][maxn];

char str[maxn*2];
int len[maxn*2];
struct node
{
    int l, r;
} f[maxn];


bool dfs(int x, int y)
{
    if(x > y) return true;
    if(dp[x][y] != -1) return dp[x][y];
    for(int i = x; i <= y; i++)
    {
        if(i-x+1 >= f[x].l && i-x+1 <= f[x].r)
        {
            if(dfs(x+1, i) && dfs(i+1, y))
            {
                dp[x][y] = 1;
                len[x] = 2*(i-x)+1;
                return true;
            }
        }
    }
    dp[x][y] = 0;
    return false;
}

///dp[i][j]表示第i个到第j个左括号是否都成功的匹配到了右括号
///对于dp[i][j] ,我们枚举i被第几个右括号匹配了.
///从i个右括号枚举到第j个右括号,假设被第k个右括号匹配并且满足之前给的范围了
///那么我们需要判断其子状态 dp[i + 1][k],以及dp[k+1][j]是可以成功匹配
int main()
{
    int n;
    while(cin >>n)
    {
        int flag = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d %d",&f[i].l, &f[i].r);
            if(!(f[i].l%2)) f[i].l++;
            if(!(f[i].r%2)) f[i].r--;
            if(f[i].l > f[i].r) flag = 1;
            f[i].l = (f[i].l+1)/2;
            f[i].r = (f[i].r+1)/2;
        }
        if(flag)
        {
            puts("IMPOSSIBLE");
            continue;
        }
        memset(dp, -1, sizeof(dp));
        memset(str, 0, sizeof(str));
        if(!dfs(1, n))
        {
            puts("IMPOSSIBLE");
            continue;
        }
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            while(str[ans] == '(' || str[ans] == ')') ++ans;
            str[ans] = '(';
            str[ans+len[i]] = ')';
        }
        puts(str);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值