AcWing.寒假每日一题

目录

1.4261孤独的照片

2.3400统计次数

         3.4366堆石头

         4.奶牛大学


1.4261孤独的照片

Farmer John 最近购入了 NN 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一。

奶牛目前排成一排,Farmer John 想要为每个连续不少于三头奶牛的序列拍摄一张照片。

然而,他不想拍摄这样的照片,其中只有一头牛的品种是更赛牛,或者只有一头牛的品种是荷斯坦牛——他认为这头奇特的牛会感到孤立和不自然。

在为每个连续不少于三头奶牛的序列拍摄了一张照片后,他把所有「孤独的」照片,即其中只有一头更赛牛或荷斯坦奶牛的照片,都扔掉了。

给定奶牛的排列方式,请帮助 Farmer John 求出他会扔掉多少张孤独的照片。

如果两张照片以不同位置的奶牛开始或结束,则认为它们是不同的。

输入格式

输入的第一行包含 N。

输入的第二行包含一个长为 N 的字符串。如果队伍中的第 i 头奶牛是更赛牛,则字符串的第 i 个字符为 G。否则,第 i 头奶牛是荷斯坦牛,该字符为 H

输出格式

输出 Farmer John 会扔掉的孤独的照片数量。

数据范围

3≤N≤5×1e5

输入样例:

5
GHGHG

输出样例:

3

样例解释

这个例子中的每一个长为 33 的子串均恰好包含一头更赛牛或荷斯坦牛——所以这些子串表示孤独的照片,并会被 Farmer John 扔掉。

所有更长的子串(GHGHHGHG 和 GHGHG)都可以被接受。

思路:

我一开始就是暴力解法,然后发现根本过不了..然后参照题解,结果是小学数奥..

思路其实很简单,分三种情况:

1.假设一段字符串是GGGHGG,那么以H为中心,孤独的照片就是3 * 2,即左边连续不同字符个数乘以右边连续不同字符个数

2.假设GGGGH,同样以H为参照,孤独照片个数为左边连续不同字符的个数 - 1

3.右边同理.

重点在代码实现!555我不会,所以...y总nb!

#include
using namespace std;
int n,l[500005],r[500005];
char s[500005];
long long ans;
int main()
{
    cin>>n>>s;
    for(int i=0,g=0,h=0;i=0;
        if(s[i]=='H'){
            r[i]=g;
            g=0;
            h++;
            //printf("g=%d h=%d r[%d]=%d\n",g,h,i,r[i]);
        }
        else{
            r[i]=h;
            h=0;
            g++;
            //printf("g=%d h=%d r[%d]=%d\n",g,h,i,r[i]);
        }
    for(int i=0;i1){
            long long cnt=(long long)l[i]*r[i]+max(0,l[i]-1)+max(0,r[i]-1);
            ans+=cnt;
        }
    cout<

l [ i ]表示第i个字符左边有多少个连续不同的字符的个数;

r [ i ]表示第i个字符右边有多少个连续不同的字符的个数;

调试代码1:

5
GGHGG
g=1 h=0 l[0]=0
g=2 h=0 l[1]=0
g=0 h=1 l[2]=2
g=1 h=0 l[3]=1
g=2 h=0 l[4]=0
g=1 h=0 r[4]=0
g=2 h=0 r[3]=0
g=0 h=1 r[2]=2
g=1 h=0 r[1]=1
g=2 h=0 r[0]=0
6

调试代码2:

5
GGHHG
g=1 h=0 l[0]=0
g=2 h=0 l[1]=0
g=0 h=1 l[2]=2
g=0 h=2 l[3]=0
g=1 h=0 l[4]=2
g=1 h=0 r[4]=0
g=0 h=1 r[3]=1
g=0 h=2 r[2]=0
g=1 h=0 r[1]=2
g=2 h=0 r[0]=0
3

只能感性理解一下了..

for(int i=0;i1){
            long long cnt=(long long)l[i]*r[i]+max(0,l[i]-1)+max(0,r[i]-1);
            ans+=cnt;
        }

这里max(0,l[i]-1)是因为如果l[i]=0的话,结果就为-1了. 最后用long long 是因为乘法可能爆int,所以要先long long,不能写成long long(l[i]*r[i]),这样就已经乘完了已经爆了.

2.3400统计次数

给定两个正整数 n 和 k,求从 1 到 n 这 n 个正整数的十进制表示中 k 出现的次数。

输入格式

共一行,包含两个整数 n 和 k。

输出格式

输出一个整数,表示答案。

数据范围

1≤n≤1e6
1≤k≤9

输入样例:

12 1

输出样例:

5

样例解释

从 1 到 12 这些整数中包含 11 的数字有 1,10,11,12,一共出现了 5 次 1。

AC代码:

#include 
using namespace std;
int main(){
    int n,k,cnt=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        int x=i;
        while(x>0){
            if(x%10==k) cnt++;
            x=x/10;
        }
    }
    printf("%d",cnt);
    return 0;
}

555我只会暴力....

第2次写这个题了,害还是会忘记int x=i; 

3.4366堆石头

题目描述

有 NN 堆石子,每堆的石子数量分别为 a1,a2,…,aN。

你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第 2,3 堆石子,则石子堆集合变为 a=[1,5,4,5]。

我们希望通过尽可能少的操作,使得石子堆集合中的每堆石子的数量都相同。

请你输出所需的最少操作次数。

本题一定有解,因为可以将所有石子堆合并为一堆。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 N。

第二行包含 N 个整数 a1,a2,…,aN。

输出格式

每组数据输出一行结果。

数据范围

1≤T≤10,
1≤N≤1e5,
0≤ai≤1e6,
ai≤1e6,
每个输入所有 N 之和不超过 1e5。

输入样例:

3
6
1 2 3 1 1 1
3
2 2 3
5
0 0 0 0 0

输出样例:

3
2
0

样例解释

第一组数据,只需要用 3 个操作来完成:

   1 2 3 1 1 1
-> 3 3 1 1 1
-> 3 3 2 1
-> 3 3 3

第二组数据,只需要用 2 个操作来完成:

   2 2 3
-> 2 5
-> 7

第三组数据,我们什么都不需要做。

思路:

设需要x次操作,因为每次操作石头堆数会-1,所以最终有N-x堆石头,每堆石头的数量为cnt=sum/N-x,所以我们枚举石头堆的数量N-x,必须为sum的约数。因每次输入所有 N 之和不超过 1e5,100000以内的约数大约为140个,数据量不大,可枚举。

那么我们怎么测试cnt作为每堆石头的数量满足条件?..

总共有sum个石头,这些石头被分成一堆一堆,每堆石头的数量必须为cnt,那么从第一个开始累加,如果a[i]cnt,说明这个cnt是不行的,换下一个。

因为我们希望操作的次数x越少,那么石头堆的数量N-x越大,cnt=sum/N-x越小。所以一旦>cnt,说明这个cnt是不行的,cnt得再大些 且是sum的约数。

AC代码:(555我是废物...)

/* 
设需要x次操作,因为每次操作石头堆数会-1,所以最终有N-x堆石头,每堆石头的数量为cnt=sum/N-x
*/
#include 
using namespace std;
int t,n,sum=0;
int a[100010];

bool check(int cnt){ //cnt代表每堆石头的数量
    int s=0;
    for(int i=1;i<=n;i++){
        s+=a[i];
        if(s>cnt) return false;
        if(s==cnt) s=0;
    }
    return true;
}

int main(){
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        int sum=0;
        scanf("%d",&n);
        for(int j=1;j<=n;j++){
            scanf("%d",&a[j]);
            sum+=a[j];
        }
    
        for (int x=0;x<=n-1;x++){
            if (sum%(n-x)== 0 && check(sum /(n-x) ) ){
                printf("%d\n", x);
                break;
            }
        }
    }
    return 0;
}

4.奶牛大学

题目描述

Farmer John 计划为奶牛们新开办一所大学!

有 N 头奶牛可能会入学。

每头奶牛最多愿意支付 ci 的学费。

Farmer John 可以设定所有奶牛入学需要支付的学费。

如果这笔学费大于一头奶牛愿意支付的最高金额,那么这头奶牛就不会入学。

Farmer John 想赚尽可能多的钱,从而可以给他的讲师提供一笔可观的工资。

请求出他能赚到的钱的数量,以及此时应当收取多少学费。

输入格式

输入的第一行包含 N。

第二行包含 NN 个整数c1,c2,…,cN,其中 ci 是奶牛 i 愿意支付的最高学费金额。

输出格式

输出 Farmer John 可以赚到的最大金额以及最优情况下他应该收取的学费。如果有多个解,输出收取学费最小的解。

注意这个问题涉及到的整数可能需要使用 64 位整数型(例如,Java 中的 “long”,C/C++ 中的 “long long”)。

数据范围

1≤N≤105,
1≤ci≤106。

输入样例:

4
1 6 4 6

输出样例:

12 4

样例解释

如果 Farmer John 收费 4,那么 3 头奶牛将会入学,从而使他赚取 3×4=12 的金额。

思路:

将a数组排序,枚举a[i]作为收取的学费,那么赚取的金额为a[i]*(n-i+1).

AC代码

#include 
#include
using namespace std;

int n,now,a[100010];
long long profit=0,ans=0;

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        
    }
    sort(a+1,a+n+1);
    
    for(int i=1;i<=n;i++){
        profit=(long long)a[i]*(n-i+1);
        if(ans

你可能感兴趣的:(c++)