Codeforces Round #323 (Div. 2) (583A,583B,582A,582B)

1.Asphalting Roads


题目链接:

http://codeforces.com/problemset/problem/583/A

解题思路:

To solve the problem one could just store two arrays hused[j] and vused[j] sized n and filled with false initially. Then process 

intersections one by one from 1 to n, and if for i-th intersections both hused[hi] and vused[vi] are false, add i to answer and set 

bothhused[hi] and vused[vi] with true meaning that hi-th horizontal and vi-th vertical roads are now asphalted, and skip asphalting 

the intersection roads otherwise.

Such solution has O(n2) complexity.

AC代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

int x[55],y[55];
vector<int> mm;

int main(){
    int n;
    while(~scanf("%d",&n)){
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        mm.clear();
        int h,v;
        for(int i = 1; i <= n*n; i++){
            scanf("%d%d",&h,&v);
            if(!x[h] && !y[v]){
                mm.push_back(i);
                x[h]++;
                y[v]++;
            }
        }
        int l = mm.size();
        for(int i = 0; i < l-1; i++)
            printf("%d ",mm[i]);
        printf("%d\n",mm[l-1]);
    }
    return 0;
}


2.Robot's Task


题目链接:

http://codeforces.com/problemset/problem/583/B

解题思路:

It is always optimal to pass all the computers in the row, starting from 1-st to n-th, then from n-th to first, then again from first to n-

th, etc. and collecting the information parts as possible, while not all of them are collected.

Such way gives robot maximal use of every direction change. O(n2) solution using this approach must have been passed system 

tests.

算法思想:

暴力来回遍历就行啦。。。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[1005],vis[1005];

int main(){
    int n;
    while(~scanf("%d",&n)){
        memset(vis,0,sizeof(vis));
        for(int i = 0; i < n; i++)
            scanf("%d",&a[i]);
        int cnt = 0,sum = 0,ans = 0,flag = 1;
        while(cnt < n){
            if(flag == 1){
                for(int i = 0; i < n; i++){
                    if(!vis[i] && a[i] <= cnt){
                        vis[i] = 1;
                        cnt++;
                    }
                }
                flag = 0;
            }
            else{
                for(int i = n-1; i >= 0; i--){
                    if(!vis[i] && a[i] <= cnt){
                        vis[i] = 1;
                        cnt++;
                    }
                }
                flag = 1;
            }
            ans++;
        }
        printf("%d\n",ans-1);
    }
    return 0;
}


3.GCD Table(贪心)


题目链接:

http://codeforces.com/problemset/problem/582/A

解题思路:

Let the answer be a1 ≤ a2 ≤ ... ≤ an. We will use the fact that gcd(ai, aj) ≤ amin(i, j).

It is true that gcd(an, an) = an ≥ ai ≥ gcd(ai, aj) for every 1 ≤ i, j ≤ n. That means that an is equal to maximum element in the table. Let 

set an to maximal element in the table and delete it from table elements set. We've deleted gcd(an, an), so the set now contains 

allgcd(ai, aj), for every 1 ≤ i, j ≤ n and 1 ≤ min(i, j) ≤ n - 1.

By the last two inequalities gcd(ai, aj) ≤ amin(i, j) ≤ an - 1 = gcd(an - 1, an - 1). As soon as set contains gcd(an - 1, an - 1), the maximum 

element in current element set is equal to an - 1. As far as we already know an, let's delete 

the gcd(an - 1, an - 1)gcd(an - 1, an),gcd(an, an - 1) from the element set. Now set contains all the gcd(ai, aj), for 

every 1 ≤ i, j ≤ n and 1 ≤ min(i, j) ≤ n - 2.

We're repeating that operation for every k from n - 2 to 1, setting ak to maximum element in the set and deleting 

the gcd(ak, ak),gcd(ai, ak)gcd(ak, ai) for every k < i ≤ n from the set.

One could prove correctness of this algorithm by mathematical induction. For performing deleting and getting maximum element 

operations one could use multiset or map structure, so solution has complexity .

算法思想:

贪心。首先用单调递减的set保存,通过观察可得,这时set里面最大的一定是原数组ans里面的值,然后对现在已有的ans里面每个元

素和刚取出来的数,进行gcd,消去set里面的最大公约数,如果set不为空,重复刚才的操作,直到set为空为止。求出ans数组即为

原数组。。。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;

multiset<int,greater<int> > s;
multiset<int,greater<int> >::iterator it;
int ans[505];

int gcd(int a,int b){
    if(b == 0)
        return a;
    else
        return gcd(b,a%b);
}

int main(){
    int n;
    while(~scanf("%d",&n)){
        int l = n*n,x;
        for(int i = 0; i < l; i++){
            scanf("%d",&x);
            s.insert(x);
        }
        int cnt = 0;
        while(!s.empty()){
            ans[cnt++] = *s.begin();
            s.erase(s.begin());
            for(int i = 0; i < cnt-1; i++){
                int tmp = gcd(ans[i],ans[cnt-1]);
                s.erase(s.find(tmp));
                s.erase(s.find(tmp));
            }
        }
        for(int i = 0; i < cnt-1; i++)
            printf("%d ",ans[i]);
        printf("%d\n",ans[cnt-1]);
    }
    return 0;
}


4.Once Again...(动态规划)

题目链接:

http://codeforces.com/problemset/problem/582/B

解题思路:

There's an alternative solution. As soon as a1, a2, ..., anT contains maximum n distinct elements, it's any non-decreasing 

subsequence has a maximum of n - 1 increasing consequtive element pairs. Using that fact, one could calculate standard longest 

non-decreasing subsequence dynamic programming on first n array blocks (a1, ..., an2) and longest non-decreasing subsequence 

DP on the last n array blocks (anT - n + 1, ..., anT). All other T - 2n blocks between them will make subsegment of consequtive equal 

elements in longest non-decreasing subsequence.

So, for fixed ai, in which longest non-decreasing subsequence of length p on first n blocks array ends, and for fixed aj ≥ ai, in which 

longest non-decreasing subsequence of length s on last n blocks array starts, we must update the answer 

with p + (T - 2n)count(ai) + s, where count(x) is the number of occurences of x in a1, ..., an array. This gives us  solution.

算法思想:

动态规划。分成三段分开处理。。。

AC代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 305;
int a[maxn];
int dp[maxn];
int n;

void update(){
    for(int i = 0; i < n; i++){
        int tmp = 0;
        for(int j = 0; j <= a[i]; j++){
            if(dp[j] > tmp)
                tmp = dp[j];
        }
        if(tmp + 1 > dp[a[i]])
            dp[a[i]] = tmp + 1;
    }
}

int main(){
    int T;
    while(~scanf("%d%d",&n,&T)){
        for(int i = 0; i < n; i++)
            scanf("%d",&a[i]);
        int time1 = min(maxn, T);
        int time3 = min(maxn, T - time1);
        int time2 = T - time1 - time3;
        for(int i = 0; i < time1; i++)
            update();
        int tmp = 0;
        if(time2 != 0){
            for(int i = 0; i < maxn; i++){
                int cnt = 0;
                for(int j = 0; j < n; j++)
                    if(a[j] == i)
                        cnt++;
                    if(dp[i] > tmp)
                        tmp = dp[i];
                dp[i] = tmp + cnt * time2;
            }
        }
        for(int i = 0; i < time3; i++)
            update();
        int res = 0;
        for(int i = 0; i < maxn; i++)
            if(dp[i] > res)
                res = dp[i];
        printf("%d\n",res);
    }
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值