第一次训练赛总结

第一题:A - LIS O(n^2) 模板
A numeric sequence of ai is ordered if a1 < a2 < … < aN. Let the subsequence of the given numeric sequence ( a1, a2, …, aN) be any sequence ( ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
Output
Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.
Sample Input
7
1 7 3 5 9 4 8
Sample Output
4

思考:这是动态规划很经典的题,之前也做过,也看到过很多次,但
还是没能很快做出来,花了我两个小时左右,开始做的时候有思路,
但是很多细节地方忘了,最后我有举了很多样例,寻找bug才通过。

代码:

#include
#include
#include
using namespace std;
int main()
{
    int s[1010];
        for(int i=1;i<1010;i++)
         s[i]=1;
    int n;
    cin>>n;
int mx;
    int a[1010];
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=2;i<=n;i++)
    {
        mx=-1;
    for(int j=i-1;j>=1;j--)
    {
        if(a[i]>a[j])
            {
                mx=max(mx,s[j]);//当时就忘了这个细节,要去前
                //面比自己小的中的最大的,我举个输入样例:
                //8
               //1 5 6 7 9 5 8 8
            }
    }
    if(mx!=-1)//这一步的也忘了判断,导致当出现了mx=-1的情况下
    //直接赋值给了s[i]
    s[i]+=mx;
    }

    cout<<*max_element(s+1,s+n+1);
    //这个*max_element()和*min_element(),用的不熟练呀。
    return 0;
}

第二题:B - 一维线性dp ++

据说在很久很久以前,可怜的兔子经历了人生中最大的打击——赛跑输给乌龟后,心中郁闷,发誓要报仇雪恨,于是躲进了杭州下沙某农业园卧薪尝胆潜心修炼,终于练成了绝技,能够毫不休息得以恒定的速度(VR m/s)一直跑。兔子一直想找机会好好得教训一下乌龟,以雪前耻。
最近正值HDU举办50周年校庆,社会各大名流齐聚下沙,兔子也趁此机会向乌龟发起挑战。虽然乌龟深知获胜希望不大,不过迫于舆论压力,只能接受挑战。
比赛是设在一条笔直的道路上,长度为L米,规则很简单,谁先到达终点谁就算获胜。
无奈乌龟自从上次获胜以后,成了名龟,被一些八卦杂志称为“动物界的刘翔”,广告不断,手头也有了不少积蓄。为了能够再赢兔子,乌龟不惜花下血本买了最先进的武器——““小飞鸽"牌电动车。这辆车在有电的情况下能够以VT1 m/s的速度“飞驰”,可惜电池容量有限,每次充满电最多只能行驶C米的距离,以后就只能用脚来蹬了,乌龟用脚蹬时的速度为VT2 m/s。更过分的是,乌龟竟然在跑道上修建了很多很多(N个)的供电站,供自己给电动车充电。其中,每次充电需要花费T秒钟的时间。当然,乌龟经过一个充电站的时候可以选择去或不去充电。
比赛马上开始了,兔子和带着充满电的电动车的乌龟并列站在起跑线上。你的任务就是写个程序,判断乌龟用最佳的方案进军时,能不能赢了一直以恒定速度奔跑的兔子。
Input
本题目包含多组测试,请处理到文件结束。每个测试包括四行:
第一行是一个整数L代表跑道的总长度
第二行包含三个整数N,C,T,分别表示充电站的个数,电动车冲满电以后能行驶的距离以及每次充电所需要的时间
第三行也是三个整数VR,VT1,VT2,分别表示兔子跑步的速度,乌龟开电动车的速度,乌龟脚蹬电动车的速度
第四行包含了N(N<=100)个整数p1,p2…pn,分别表示各个充电站离跑道起点的距离,其中0 其中每个数都在32位整型范围之内。
Output
当乌龟有可能赢的时候输出一行 “What a pity rabbit!”。否则输出一行"Good job,rabbit!";
题目数据保证不会出现乌龟和兔子同时到达的情况。
Sample Input
100
3 20 5
5 8 2
10 40 60
100
3 60 5
5 8 2
10 40 60
Sample Output
Good job,rabbit!
What a pity rabbit!
思考:这一题我没写出来,当时前面的思路对了,代码写了一半,到关键部分对每个最短时间的选择卡壳了,因为写第一题浪费了太长时间,没有太多的时间思考了,而且这个最短时间的选择感觉很复杂,觉得自己短时间写不出来,不过看到正确代码的时候,又觉得当时是真写不出来,我感觉当时想不到的就是这一步:if(j)time+=T;而这一步猛一看是对每一个加电站都加电,但其并不是,这是一维dp呀,在对每一次dp[i],都会对i之前的部分找最小dp[j]的加上,而在这个所谓的time++T;其实正是在dp[j]这个站点加电,而在j到i之间的充电站就是没有选择充电的站呀,还是自己对dp理解不深。
昨天晚上理解的题,到第二天再自己去写总出现大的小的错误,。
代码:

#include
#include
#include
using namespace std;
int main()
{
    int l;
    while(scanf("%d",&l)!=EOF)
    {
        int n,c,t,vr,vt1,vt2;
        double p[110];
        memset(p,0,sizeof(p));
        int s[110];
        cin>>n>>c>>t;
        cin>>vr>>vt1>>vt2;
        for(int i=1;i<=n;i++)
            cin>>s[i];
            s[0]=0;
            s[n+1]=l;
        double t1=l*1.0/vr;//第一个错误就是把1.0写成了10,浪费我一个多小时/。
        for(int i=1;i<=n+1;i++)
        {
            double minn=9999999;
            for(int j=0;j<i;j++)
        {
            double t2=0;//这里也有个错误,每次循环j的时候应该初始化t2,或者把下面判单x与c时,t2=什么,而不是+=什么!
            int x=s[i]-s[j];
            if(x>c)
            t2=(c*1.0/vt1+(x-c)*1.0/vt2);
            //还有一个特别恶心人的错误,就是将int通过*1.0转换为double时应该先转换再计算而不是在除过之后再*1.0。
            else
            t2=(x*1.0/vt1);
            if(j)
            t2+=t;
            if(minn>p[j]+t2)
            {
                minn=p[j]+t2;//错误2是个大错误,这里的minn应该指的是到p[i]时的最短时间,而不是上一个站点到这个站点的最短
                //时间。好好理解理解。
            }
        }
         p[i]=minn;
        }

            if(p[n+1]>=t1)
                cout<<"Good job,rabbit!"<<endl;
            else
                cout<<"What a pity rabbit!"<<endl;
    }
    return 0;
}

第三题:C - Frog Jumping
A frog is currently at the point 0 on a coordinate axis Ox. It jumps by the following algorithm: the first jump is a units to the right, the second jump is b units to the left, the third jump is a units to the right, the fourth jump is b units to the left, and so on.

Formally:

if the frog has jumped an even number of times (before the current jump), it jumps from its current position x to position x+a;
otherwise it jumps from its current position x to position x−b.
Your task is to calculate the position of the frog after k jumps.

But… One more thing. You are watching t different frogs so you have to answer t independent queries.

Input
The first line of the input contains one integer t (1≤t≤1000) — the number of queries.

Each of the next t lines contain queries (one query per line).

The query is described as three space-separated integers a,b,k (1≤a,b,k≤109) — the lengths of two types of jumps and the number of jumps, respectively.

Output
Print t integers. The i-th integer should be the answer for the i-th query.

Example
Input

6
5 2 3
100 1 4
1 10 5
1000000000 1 6
1 1 1000000000
1 1 999999999
Output
8
198
-17
2999999997
0
1
Note
In the first query frog jumps 5 to the right, 2 to the left and 5 to the right so the answer is 5−2+5=8.

In the second query frog jumps 100 to the right, 1 to the left, 100 to the right and 1 to the left so the answer is 100−1+100−1=198.

In the third query the answer is 1−10+1−10+1=−17.

In the fourth query the answer is 109−1+109−1+109−1=2999999997.

In the fifth query all frog’s jumps are neutralized by each other so the answer is 0.

The sixth query is the same as the fifth but without the last jump so the answer is 1
思考.:我一开始准备模拟一遍然后看了时间复杂度太大了,超时了,就当作数学计算了,注意用long long。
代码:

#include
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        long long a,b,k;
        cin>>a>>b>>k;
        long long ans=0;

        if(k%2==1)
        {
            ans=((k/2)+1)*a-(k/2)*b;
        }
        else
        {
            ans=(k/2)*a-(k/2)*b;
        }
        cout<<ans<<endl;
    }
    return 0;
}

第四题:D - Disturbed People
There is a house with n flats situated on the main street of Berlatov. Vova is watching this house every night. The house can be represented as an array of n integer numbers a1,a2,…,an, where ai=1 if in the i-th flat the light is on and ai=0 otherwise.

Vova thinks that people in the i-th flats are disturbed and cannot sleep if and only if 1

Vova is concerned by the following question: what is the minimum number k such that if people from exactly k pairwise distinct flats will turn off the lights then nobody will be disturbed? Your task is to find this number k.

Input
The first line of the input contains one integer n (3≤n≤100) — the number of flats in the house.

The second line of the input contains n integers a1,a2,…,an (ai∈{0,1}), where ai is the state of light in the i-th flat.

Output
Print only one integer — the minimum number k such that if people from exactly k pairwise distinct flats will turn off the light then nobody will be disturbed.

Examples
Input

10
1 1 0 1 1 0 1 0 1 0
Output
2
Input
5
1 1 0 0 0
Output
0
Input
4
1 1 1 1
Output
0
Note
In the first example people from flats 2 and 7 or 4 and 7 can turn off the light and nobody will be disturbed. It can be shown that there is no better answer in this example.

There are no disturbed people in second and third examples.
**思考:**当时写这题的时候已经被前面的打击的不行了,而且时间也不多了,当时想到了贪心,但是 没有想到怎么贪,不敢想,当时认为贪心都是特别巧妙的,不认为自己能想出来,自信已经没了‍。但是这一题的贪心很简单,每次优先吧右边的1变为零就行了。
代码:

#include
using namespace std;
int a[110];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    int s=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i-1]==1&&a[i]==0&&a[i+1]==1)
        {
            a[i+1]=0;//改变!
            s++;
        }
    }
    cout<<s;
    return 0;
}

第五题:E - Good Array

Let’s call an array good if there is an element in the array that equals to the sum of all other elements. For example, the array a=[1,3,3,7] is good because there is the element a4=7 which equals to the sum 1+3+3.

You are given an array a consisting of n integers. Your task is to print all indices j of this array such that after removing the j-th element from the array it will be good (let’s call such indices nice).

For example, if a=[8,3,5,2], the nice indices are 1 and 4:

if you remove a1, the array will look like [3,5,2] and it is good;
if you remove a4, the array will look like [8,3,5] and it is good.
You have to consider all removals independently, i. e. remove the element, check if the resulting array is good, and return the element into the array.

Input
The first line of the input contains one integer n (2≤n≤2⋅105) — the number of elements in the array a.

The second line of the input contains n integers a1,a2,…,an (1≤ai≤106) — elements of the array a.

Output
In the first line print one integer k — the number of indices j of the array a such that after removing the j-th element from the array it will be good (i.e. print the number of the nice indices).

In the second line print k distinct integers j1,j2,…,jk in any order — nice indices of the array a.

If there are no such indices in the array a, just print 0 in the first line and leave the second line empty or do not print it at all.

Examples
Input

5
2 5 1 2 2
Output
3
4 1 5
Input
4
8 3 5 2
Output
2
1 4
Input
5
2 1 2 4 3
Output
0

Note
In the first example you can remove any element with the value 2 so the array will look like [5,1,2,2]. The sum of this array is 10 and there is an element equals to the sum of remaining elements (5=1+2+2).

In the second example you can remove 8 so the array will look like [3,5,2]. The sum of this array is 10 and there is an element equals to the sum of remaining elements (5=3+2). You can also remove 2 so the array will look like [8,3,5]. The sum of this array is 16 and there is an element equals to the sum of remaining elements (8=3+5).

In the third example you cannot make the given array good by removing exactly one element.
**思考:**这题当时我没看,不过当时看了也写不出来,这题我看的第一个思路,使用priority_queue但是再遍历的时候我不会通过迭代器,对数列中的数操作,再看自己的笔记的时候看到了之前学的multiset,可以方便的通过迭代器操。思路:首先定义一个结构体保存输入数组的值和位置,然后保存到multiset中,并且定义一个ans保存数组的总和,然后遍历multiset,注意定义将multiset从小到大排列,从小到大排序方便了判断,每次判断删除一个的时候就看最后一项是不是等于剩余项之和就行了。
代码:

#include
#include
#include
#include
using namespace std;
const int maxn=1e6+10;
struct D
{
    int a,b;
}d[maxn];
    int r[maxn];
    struct cmp{//这个时multiset中排序的固定结构要记住。

       bool operator()(const D&x,const D&y)const
    {
        return x.a<y.a;
    }


    };

int main()
{
    int n;
    cin>>n;
    multiset<D,cmp > q;
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        cin>>d[i].a;
        ans+=d[i].a;
        d[i].b=i;
        q.insert(d[i]);
    }
    int k=0;

    D m1=*(--q.end());
    D m2=*(--(--q.end()));//这不能直接减我就只能这样减两次了
    //显得很笨但是可以用。
    for(multiset<D,cmp>::iterator i=q.begin();i!=q.end();i++)
    {
        if(i!=--q.end())
        {
            if(ans-(*i).a-m1.a==m1.a)
                {
                    k++;
                    r[k]=(*i).b;
                }
        }
        else
        {
            if(ans-(*i).a-m2.a==m2.a)//迭代器先取*再引用结构
            //体中的内容
            {
                k++;
                r[k]=(*i).b;
            }
        }
    }
    cout<<k<<endl;
    for(int i=1;i<=k;i++)
        cout<<r[i]<<" ";
    return 0;
}

第六题:F - Cutting Out
You are given an array s consisting of n integers.

You have to find any array t of length k such that you can cut out maximum number of copies of array t from array s.

Cutting out the copy of t means that for each element ti of array t you have to find ti in s and remove it from s. If for some ti you cannot find such element in s, then you cannot cut out one more copy of t. The both arrays can contain duplicate elements.

For example, if s=[1,2,3,2,4,3,1] and k=3 then one of the possible answers is t=[1,2,3]. This array t can be cut out 2 times.

To cut out the first copy of t you can use the elements [1,2−−,3,2,4,3−−,1−−] (use the highlighted elements). After cutting out the first copy of t the array s can look like [1,3,2,4].
To cut out the second copy of t you can use the elements [1−−,3−−,2−−,4]. After cutting out the second copy of t the array s will be [4].
Your task is to find such array t that you can cut out the copy of t from s maximum number of times. If there are multiple answers, you may choose any of them.

Input
The first line of the input contains two integers n and k (1≤k≤n≤2⋅105) — the number of elements in s and the desired number of elements in t, respectively.

The second line of the input contains exactly n integers s1,s2,…,sn (1≤si≤2⋅105).

Output
Print k integers — the elements of array t such that you can cut out maximum possible number of copies of this array from s. If there are multiple answers, print any of them. The required array t can contain duplicate elements. All the elements of t (t1,t2,…,tk) should satisfy the following condition: 1≤ti≤2⋅105.

Examples
Input

7 3
1 2 3 2 4 3 1
Output
1 2 3
Input
10 4
1 3 1 3 10 3 7 7 12 3
Output
7 3 1 3
Input
15 2
1 2 1 1 1 2 1 1 2 1 2 1 1 1 1
Output
1 1
Note
The first example is described in the problem statement.

In the second example the only answer is [7,3,1,3] and any its permutations. It can be shown that you cannot choose any other array such that the maximum number of copies you can cut out would be equal to 2.

In the third example the array t can be cut out 5 times.
思路:首先保存数出现的次数,再通过二分法找出最大的次数,再将出现大于等于最大次数的数输出k个。里面有很多细节。
代码:

#include
#include
using namespace std;
const int maxn=2e5+10;
int s[maxn],rs[maxn];
int n,k;
bool check(int x)
{
    long long ans=0;
    for(int i=1;i<maxn;i++)
        ans+=s[i]/x;//因为在结果数组中是能重复的。因此这里要除。
    return ans>=k;//x出现的最大次数,k是出现最大次数的次数。我粗心把这里的k写成了x。
    //真的恶心。
}
int main()
{
    cin>>n>>k;
    int p;
    for(int i=1;i<=n;i++)
    {
        cin>>p;
        s[p]++;
    }
    int l,r,mid;
    l=1,r=n;//出现次数,那么最大就是n
    int resu=1;//这里一定要定义一个数在二分法中等于mid,
    //注意用resu的话要初始化resu。所以我现在感觉貌似通过l或者r改变好用。
    //因为这里的范围是向右取得,所以最终的r和l比你要取的值大一的,最终的mid是上一个r和l的中间值
    //因此这里要用一个resu来,或者直接让最后的r--或者l--来用。
    //因此以后写二分法要判断一下你要去的值是在左边还是右边!!!!!很重要。
    while(r>=l)//这个大于等于再判断说明一下
    {
        mid=(r-l)/2+l;//这样写比(r+l)/2更好防止r+l超过int范围.
        if(check(mid))
            resu=mid,l=mid+1;
        else
            r=mid-1;
    }
    long long cnt=0;
        for(int i=1;i<maxn;i++)
        {
            if(s[i]>=resu)
            {
                for(int j=1;j<=s[i]/resu;j++)
                {
                    rs[++cnt]=i;
                    if(cnt==k)
                break;
                }
            }
            if(cnt==k)
                break;//减少时间复杂度,可写可不写。
        }
    for(int i=1;i<=cnt;i++)
        cout<<rs[i]<<" ";
        return 0;
}

第七题:G - Thematic Contests
Polycarp has prepared n competitive programming problems. The topic of the i-th problem is ai, and some problems’ topics may coincide.

Polycarp has to host several thematic contests. All problems in each contest should have the same topic, and all contests should have pairwise distinct topics. He may not use all the problems. It is possible that there are no contests for some topics.

Polycarp wants to host competitions on consecutive days, one contest per day. Polycarp wants to host a set of contests in such a way that:

number of problems in each contest is exactly twice as much as in the previous contest (one day ago), the first contest can contain arbitrary number of problems;
the total number of problems in all the contests should be maximized.
Your task is to calculate the maximum number of problems in the set of thematic contests. Note, that you should not maximize the number of contests.

Input
The first line of the input contains one integer n (1≤n≤2⋅105) — the number of problems Polycarp has prepared.

The second line of the input contains n integers a1,a2,…,an (1≤ai≤109) where ai is the topic of the i-th problem.

Output
Print one integer — the maximum number of problems in the set of thematic contests.

Examples
Input
18
2 1 2 10 2 10 10 2 2 1 10 10 10 10 1 1 10 10
Output
14
Input
10
6 6 6 3 6 1000000000 3 3 6 6
Output
9
Input
3
1337 1337 1337
Output
3
Note
In the first example the optimal sequence of contests is: 2 problems of the topic 1, 4 problems of the topic 2, 8 problems of the topic 10.

In the second example the optimal sequence of contests is: 3 problems of the topic 3, 6 problems of the topic 6.

In the third example you can take all the problems with the topic 1337 (the number of such problems is 3 so the answer is 3) and host a single contest.
**思路:**这题和输入的数无关重点在于数的次数,因此在统计数的次数之后,就无需管数本身了,难点就在求最大的次数,方法是,从1到n依次枚举,并统计每次枚举时的次数之和,最后取最大的次数之和输出。
**说明:**本来我想的用b[a[i]]++记录次数,但是a[i]可以很大超过了数组范围,跟何况,这题和a[i]无关,就算有关的话,以后用pair来记录原数和次数,注意pair头文件要写。
代码:

#include
#include
using namespace std;
const int maxn=2e5+10;
int a[maxn],b[maxn];//将次数保存到b[]里面,只考虑次数。
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    int k=1;
    sort(a+1,a+n+1);//送小到大
    for(int i=1;i<=n;i++)
    {
        b[k]++;
        if(a[i]!=a[i+1])
            k++;
    }
    sort(b+1,b+k);//从小到大
    long long ans=0;

for(int i=1;i<=n;i++)//枚举所有可能性。
{
    long long s=0;
    int l=1;
    for(int j=i;j<=n;j*=2)//这个就取j<=n,不用害怕总和超过n,下面会判断,超的话就会断开循环。
    {
        int pos=lower_bound(b+l,b+k,j)-b;//返回的是大于等于j的位置,如果都小于j就返回k。
        if(pos==k)
            break;
            s+=j;
            l=pos+1;//注意这个,每取一次数都要往前推,防止重复取。

    }
    ans=max(ans,s);
}
    cout<<ans;
    return 0;
}

你可能感兴趣的:(第一次训练赛总结)