Codeforces Round #407 (Div. 2) (A-E) ( 水模拟 + 复杂模拟/multiset优化 + dp + 欧拉路 + 平均数处理bfs)

昨天训练的题目,今天终于把题补完了。补完之后又忍不住骂了自己几句智障,感觉很不是状态。

然后立一个flag吧,之后所有的cf div2的题全部补完,不会的看题解补,为区域赛准备。今年作为coder之后压力还是比较大的,不过也是一个比较好的提高的机会吧,累并快乐着。

A. Anastasia and pebbles

Anastasia loves going for a walk in Central Uzhlyandian Park. But she became uninterested in simple walking, so she began to collect Uzhlyandian pebbles. At first, she decided to collect all the pebbles she could find in the park.

She has only two pockets. She can put at most k pebbles in each pocket at the same time. There are n different pebble types in the park, and there are wi pebbles of the i-th type. Anastasia is very responsible, so she never mixes pebbles of different types in same pocket. However, she can put different kinds of pebbles in different pockets at the same time. Unfortunately, she can't spend all her time collecting pebbles, so she can collect pebbles from the park only once a day.

Help her to find the minimum number of days needed to collect all the pebbles of Uzhlyandian Central Park, taking into consideration that Anastasia can't place pebbles of different types in same pocket.

Input

The first line contains two integers n and k (1 ≤ n ≤ 1051 ≤ k ≤ 109) — the number of different pebble types and number of pebbles Anastasia can place in one pocket.

The second line contains n integers w1, w2, ..., wn (1 ≤ wi ≤ 104) — number of pebbles of each type.

Output

The only line of output contains one integer — the minimum number of days Anastasia needs to collect all the pebbles.

Examples
input
Copy
3 2
2 3 4
output
Copy
3

A题: 有n种石子,容量为k的口袋,每个口袋中不能放不同种类的石子,一天最多装两口袋,问最少几天装完。

对于所有的 a[i] 我们至少需要装a[i]/i+1次,对于所有的a[i]&1==1的石子需要多装一次,然后一天最多两次,end。

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

const int maxn = 1e5+5;
const double Pi = acos(-1.0);
const double eps = 1e-8;

int a[maxn];

int main()
{
    cin.sync_with_stdio(false);
    int n, k, sum=0;
    cin>>n>>k;
    for(int i=0; i<n; i++)
    {
        cin>>a[i];
        sum += a[i]/k;
        if(a[i]%k) sum++;
    }

    cout<<(sum+1)/2<<endl;
}

昨天刚学会的cin.sync_with_stdio(false)所以会一直在用,一个是为了加快自己的速度,另外一个是因为队友比较习惯用cin cout,大家编码习惯还是统一一点比较好,对于对时间要求较高的题目,还是推荐使用 scanf 或者 fastIO

B. Masha and geometric depression

Masha really loves algebra. On the last lesson, her strict teacher Dvastan gave she new exercise.

You are given geometric progression b defined by two integers b1 and q. Remind that a geometric progression is a sequence of integers b1, b2, b3, ..., where for each i > 1 the respective term satisfies the condition bi = bi - 1·q, where q is called the common ratio of the progression. Progressions in Uzhlyandia are unusual: both b1 and q can equal 0. Also, Dvastan gave Masha m "bad" integers a1, a2, ..., am, and an integer l.

Masha writes all progression terms one by one onto the board (including repetitive) while condition |bi| ≤ l is satisfied (|x| means absolute value of x). There is an exception: if a term equals one of the "bad" integers, Masha skips it (doesn't write onto the board) and moves forward to the next term.

But the lesson is going to end soon, so Masha has to calculate how many integers will be written on the board. In order not to get into depression, Masha asked you for help: help her calculate how many numbers she will write, or print "inf" in case she needs to write infinitely many integers.

Input

The first line of input contains four integers b1qlm (-109 ≤ b1, q ≤ 1091 ≤ l ≤ 1091 ≤ m ≤ 105) — the initial term and the common ratio of progression, absolute value of maximal number that can be written on the board and the number of "bad" integers, respectively.

The second line contains m distinct integers a1, a2, ..., am (-109 ≤ ai ≤ 109) — numbers that will never be written on the board.

Output

Print the only integer, meaning the number of progression terms that will be written on the board if it is finite, or "inf" (without quotes) otherwise.

Examples
input
Copy
3 2 30 4
6 14 25 48
output
Copy
3

B题:给定数列第一项b1和公比q,绝对值的上界l以及m个hate的数字。要求顺序求出数列的各项,当任意一项绝对值大于l时停止,如果不是hate的数字就标记,问足够长的时间后,标记数字的个数。如果无限则输出inf

一开始想到的是,如果公比为0 1 -1则有可能出现无限的情况,其余情况就算是极限数据也是log级别的完全可以暴力出来。那么就分公比情况进行模拟,暴力求解。但是因为自己不细致+没有认真分情况一连WA了6发。然后决定转用multiset优化一发过了。

基本思路,如果一个数出现了10次以上,我们就可以认为出现循环了(其实3次就可以判循环,这里是随手写的)。不出现循环则我可以模拟暴力求解,出现循环时,如果我标记的数字个数大于1个,则是inf,否则的话照样输出标记计数。原因是因为可能会出现所有值都hate,或者第一个值不hate,公比q为0,0是hate。  End

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

const int maxn = 1e5+5;
const double Pi = acos(-1.0);
const double eps = 1e-8;

set<long long >s1;
multiset<long long>s3, s2;
int abs(int x) { return x<0?-x:x;}

int main()
{
    cin.sync_with_stdio(false);

    long long n, q, l, m, sum=0;
    bool inf = false;
    cin>>n>>q>>l>>m;
    for(int i=0; i<m; i++)
    {
        int num;
        cin>>num;
        s1.insert(num);
    }

    long long x = n;

    while(abs(n)<=l)
    {
        if(!s1.count(n)) sum++;
        if(s2.count(n)>=10) {
            if(sum>1) inf = true;
            break;
        }

        s2.insert(n);
        n *= q;
    }

//    if(((q==0 && !s1.count(0)) || (q==1 && !s1.count(n)) || (q==-1 && (!s1.count(n) || !s1.count(-n)))) && abs(x)<=l) puts("inf");
    if(inf) puts("inf");
    else cout<<sum<<endl;

}

注释掉部分就是一开始模拟时候开的坑,到最后都没有模拟过去,膜拜所有昨天过题的大佬,我看了一眼都是模拟过得,代码能力maxx。

C. Functions again

Something happened in Uzhlyandia again... There are riots on the streets... Famous Uzhlyandian superheroes Shean the Sheep and Stas the Giraffe were called in order to save the situation. Upon the arriving, they found that citizens are worried about maximum values of the Main Uzhlyandian Function f, which is defined as follows:

In the above formula, 1 ≤ l < r ≤ n must hold, where n is the size of the Main Uzhlyandian Array a, and |x| means absolute value of x. But the heroes skipped their math lessons in school, so they asked you for help. Help them calculate the maximum value of f among all possible values of l and r for the given array a.

Input

The first line contains single integer n (2 ≤ n ≤ 105) — the size of the array a.

The second line contains n integers a1, a2, ..., an (-109 ≤ ai ≤ 109) — the array elements.

Output

Print the only integer — the maximum value of f.

Examples
input
Copy
5
1 4 2 3 1
output
Copy
3

C题:给定一个数列,定义了一种运算f(l, r) ,对于任意对 (l, r) 我们可以得到一个函数值,问其中最大的是多少。

基本思路,对于一个给定的数列,求其连续区间的最大和,我们可以直接用dp去解,而这道题不同的地方在于,这个序列是不定的,通过对公式的分析我们发现,对于固定的位置,它取值的正负性只和l的奇偶性有关,那么我们可以根据l奇偶性的不同得到两个新的序列,然后对这两个序列进行dp。需要注意的是,因为我们的新序列是根据起点的奇偶性来的,所以我们最好使用倒序dp的方式,即从原来以某一位为结尾连续序列最大和的想法,转换为以某一位为起点,连续序列最大和。End

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

const int maxn = 1e5+5;
const double Pi = acos(-1.0);
const double eps = 1e-8;
const int mod = 1e9+7;
const int INF = 0x3f3f3f3f;

//LL abs(LL x){return x<0?-x:x;}

LL a[maxn], b[maxn], c[maxn];
LL dp[maxn];

int main()
{
    cin.sync_with_stdio(false);
    int n;
    LL ans = -mod;
    cin>>n;
    for(int i=0; i<maxn; i++)
        dp[i] = -mod;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    for(int i=1; i<n; i++)
    {
        LL x=abs(a[i]-a[i+1]);
        if(i%2)
        {
            b[i]=x;
            c[i]=-x;
        }
        else
        {
            b[i]=-x;
            c[i]=x;
        }
    }
    for(int i=n-1; i>=1; i--)
    {
        if(i&1)
        {
            dp[i]=b[i];
            if(i+2<n)
                dp[i] = max(dp[i], b[i]+b[i+1]+dp[i+2]);
        }
        else
        {
            dp[i]=c[i];
            if(i+2<n)
                dp[i] = max(dp[i], c[i]+c[i+1]+dp[i+2]);
        }
        ans = max(ans, dp[i]);
    }
    cout<<ans<<endl;

}
D. Weird journey

Little boy Igor wants to become a traveller. At first, he decided to visit all the cities of his motherland — Uzhlyandia.

It is widely known that Uzhlyandia has n cities connected with m bidirectional roads. Also, there are no two roads in the country that connect the same pair of cities, but roads starting and ending in the same city can exist. Igor wants to plan his journey beforehand. Boy thinks a path is good if the path goes over m - 2 roads twice, and over the other 2 exactly once. The good path can start and finish in any city of Uzhlyandia.

Now he wants to know how many different good paths are in Uzhlyandia. Two paths are considered different if the sets of roads the paths goes over exactly once differ. Help Igor — calculate the number of good paths.

Input

The first line contains two integers nm (1 ≤ n, m ≤ 106) — the number of cities and roads in Uzhlyandia, respectively.

Each of the next m lines contains two integers u and v (1 ≤ u, v ≤ n) that mean that there is road between cities u and v.

It is guaranteed that no road will be given in the input twice. That also means that for every city there is no more than one road that connects the city to itself.

Output

Print out the only integer — the number of good paths in Uzhlyandia.

Examples
input
Copy
5 4
1 2
1 3
1 4
1 5
output
Copy
6

D题:给定n个点m条边,m条边中,选择其中两条边只走一次,其余边走两次的连续走法有多少种。当只走一次的两边所组成的集合是不同的的时候,我们认为两种走法是不同的。

基本思路:这道题场上没有A出来,场下也是看了题解才懂,再次对场上A题大佬表示敬意。连续走法第一反应应该是欧拉路,而既然其余边要走两次,我们就直接给每条边加一个复制,然后选择其中两条边后判断是否满足欧拉路的条件: 奇点的个数为0个或两个. 那么我们现在讨论选择边对于奇点个数的影响.

1. 不相邻的两条普通边: 奇点数为4 不满足

2. 相邻的两条普通边: 奇点数为2  满足

3. 一条普通边和一条自环: 奇点数为2 满足

4. 两条自环: 奇点数为0  满足

那么我们就可以记录出所有我们需要的数据, 同一个顶点有多少条边, 一共有多少个自环, 然后直接求解.

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

const int maxn = 1e6+5;

int pre[maxn], cnt[maxn];

int found(int x)
{
    if(pre[x]==-1) {
        pre[x] = x;
        return x;
    }
    else if(pre[x] == x) return x;
    return pre[x] = found(pre[x]);
}

void join(int x, int y)
{
    int x1 = found(x);
    int y1 = found(y);
    if(x1==y1) return ;
    else {
        pre[x1] = y1;
        return ;
    }
}

int main()
{

    cin.sync_with_stdio(false);

    int n, m, loop=0, sum = 0;
    memset(pre, -1, sizeof pre);
    LL ans = 0;

    cin>>n>>m;
    while(m--)
    {
        int s, t;
        cin>>s>>t;
        if(s == t){
            loop ++;
        }
        else {
            cnt[s]++;
            cnt[t]++;
            sum++;
        }
        join(s, t);
    }

    int flag = 0;

    for(int i=1; i<=n; i++){
        //cout<<i<<": "<<pre[i]<<endl;
        if(pre[i]==i) flag++;
    }

    if(flag > 1) ;
    else{
        for(int i=1; i<=n; i++){
            if(cnt[i]>=2) ans += (LL)cnt[i]*(cnt[i]-1)/2;
            //cout<<i<<": "<<cnt[i]<<" "<<ans<<endl;
        }
        ans += (LL)loop*sum;
        ans += (LL)loop*(loop-1)/2;
    }
    cout<<ans<<endl;
}

这里我用了并查集来判连通性,用数组记录每边的度。需要注意的是,题目只限定走边不需要走完所有的定点,以及如果边组成了两个以上的连通块则一定不行,输出-1。

E. The Great Mixing

Sasha and Kolya decided to get drunk with Coke, again. This time they have k types of Coke. i-th type is characterised by its carbon dioxide concentration . Today, on the party in honour of Sergiy of Vancouver they decided to prepare a glass of Coke with carbon dioxide concentration . The drink should also be tasty, so the glass can contain only integer number of liters of each Coke type (some types can be not presented in the glass). Also, they want to minimize the total volume of Coke in the glass.

Carbon dioxide concentration is defined as the volume of carbone dioxide in the Coke divided by the total volume of Coke. When you mix two Cokes, the volume of carbon dioxide sums up, and the total volume of Coke sums up as well.

Help them, find the minimal natural number of liters needed to create a glass with carbon dioxide concentration . Assume that the friends have unlimited amount of each Coke type.

Input

The first line contains two integers nk (0 ≤ n ≤ 10001 ≤ k ≤ 106) — carbon dioxide concentration the friends want and the number of Coke types.

The second line contains k integers a1, a2, ..., ak (0 ≤ ai ≤ 1000) — carbon dioxide concentration of each type of Coke. Some Coke types can have same concentration.

Output

Print the minimal natural number of liter needed to prepare a glass with carbon dioxide concentration , or -1 if it is impossible.

Examples
input
Copy
400 4
100 300 450 500
output
Copy
2

E题: E题一开始没有敢切,但是仔细分析之后就会发现其实也是一个比较简单的题。题意,给出n个数,求从中最少选多少个数可以使得他们的平均数为k。

基本思路:对于若干数构造平均数为k的例子,我们可以预先对这n个数进行处理,为 a[i] = n-a[i] 这样处理的原因是我们可以将每个数对平均数的贡献记录下来,当这种贡献为0时即平均数为0 。这样处理的好处是,我们省去了计算平均数的步骤。然后我们就可以用一个set存下这些可能的贡献,然后进行bfs。

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

const int maxn = 1e6+5;
int a[maxn];
int vis[1005];
int n, k;

set<int >s;

int bfs()
{
    queue<int >q;
    q.push(0);
    vis[0] = 0;
    while(!q.empty())
    {
        int now = q.front();
        q.pop();
        //cout<<"**"<<now<<endl;

        for(set<int>::iterator it=s.begin(); it!=s.end(); it++)
        {
            int next = now + *it;
            if(next<0 || vis[next]) continue;
            else{
                if(next == 0) return vis[now]+1;

                vis[next] = vis[now] + 1;
                q.push(next);
            }
        }
    }
    return -1;
}

int main()
{

    //freopen("in.txt", "r", stdin);

    cin.sync_with_stdio(false);
    s.clear();
    cin>>k>>n;
    for(int i=0; i<n; i++){
        cin>>a[i];
        s.insert(a[i] - k);
    }

    cout<<bfs()<<endl;
}

需要注意的是,这道题中的数均为整数,而贡献有正有负, 我们看可以只记录贡献为正的情况,bfs到0 (贡献为负开始到0只是这个过程的逆序),这样的好处是我们就可以用vis数组记录每一个状态的步数了。因为下标不可以是负的。然后这道题中的数据贡献只有可能是[-1000, 1000],中一个长度为1000的子区间。而m的数据范围却有1e6。所以我们用了set之后可以减少遍历所小号的时间。



End  争取补出所有div2

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值