A.小锋的书

问一个字符串中有没有连续的七个及以上的”1”或”0”,只需要定义两个变量记录连续最大的”1”和”0”的数量即可。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
 
char st[1000];
 
int main() {
    scanf("%s",st);
    int zero=0,one=0,maz=0,mao=0; 
//这里有四个变量,zero和one记录遍历过程中,连续的1和0的数量
//maz和mao则记录连续的0串和1串最大长度
    for(int i=0;i<strlen(st);i++){ //遍历字符串
        if(st[i]=='1'){
            one++;    //如果是1,”1”串长度++
            if(one>mao)mao=one;  //同时如果大于最大长度,更新mao
            zero=0;   //遇到1的话说明0串中断了,zero 归零
        }else {
            zero++;   //这一部分和上面同理
            if(zero>maz)maz=zero;
            one=0;
        }
    }
    if(mao>=7||maz>=7)printf("YES");//简单的输出
    else printf("NO");
    return 0;
}

B.大海我来了

根据每个人所属的类别先后输出不同类的人名,可以按照题目要求的顺序,进行四次循环判断。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

struct po//定义结构体存储每个人的名字和类别
{
    char name[19],rank[19];
}per[109];
int vis[109];/*定义一个记录输出情况的数组,在这里仅用这个数组判断哪个是未输出的船长。*/
/*我们也可以利用这个数组实现一种可能更简单的方法,在读入时将这四类人记为1,2,3,4,然后分别存入数组,之后每次判断输出时只需要用这个数组进行判断即可。*/

int main() {
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s %s",per[i].name,per[i].rank); 
    }
    for(int i=1;i<=n;i++){
        if(!strcmp(per[i].rank,"rat")){
       /*这里使用的是strcmp()函数,不懂使用方法可百度*/
            vis[i]=1;  //这个数组把已经输出的第i个人记为1,而其他未输出为0
            printf("%s\n",per[i].name);
        }
    }
    for(int i=1;i<=n;i++){
        if(!strcmp(per[i].rank,"child")||!strcmp(per[i].rank,"woman")){
            vis[i]=1;
            printf("%s\n",per[i].name);
        }
    }
    for(int i=1;i<=n;i++){
        if(!strcmp(per[i].rank,"man")){
            vis[i]=1;
            printf("%s\n",per[i].name);
        }
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){ //最后1个仍未输出的即是船长
            printf("%s\n",per[i].name);
	        break;
        }
    }
	return 0;
}

C.拔河比赛

这道题很简单,只需要判断三个方向上的合力是否都为零,如果都为0,则受力平衡。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


int main() {
    int n,x=0,y=0,z=0,a,b,c;//x,y,z要赋值为0
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&a,&b,&c);
        x+=a,y+=b,z+=c; //累加
    }
    if(!x&&!y&&!z)printf("YES\n");//简单的判断三个方向的合力是否都为0
    else printf("NO\n");
    return 0;
}

D.子序列和

枚举子序列计算总和的方式显然不现实,考虑枚举每位a[i]最总和造成的贡献。

假设包含a[i]的子序列共有k个,那么a[i]的贡献值便为a[i]*k;

假设对于当前子序列,a[i]已经选了,那么其他所有元素都有选和不选两种情况,最后包含的a[i]的子序列便有2n12^{n-1}个,n为序列总长度。

举例如 a1,a2,a3,a4a1,a2,a3,a4,求包含 a1a1 的子序列共有多少个,那么 a2a2 选不选会分出来两种情况为{a1}\{a1\}{a1,a2}\{a1,a2\}a3a3 选不选又分出来更多的情况,为{a1},{a1,a3}{a1,a2},{a1,a2,a3}\{a1\},\{a1,a3\}\{a1,a2\},\{a1,a2,a3\}a4a4 同理,所以除了aiai 以外其他元素要考虑n-1次,最后包含ai的子序列共有2n12^{n-1} 个。

另一方面,计算 2n12^{n-1} 次方本题中可以在算每一位的贡献之前预处理出来,即开个for循环n次用一个数组p[ ]p[\ ]pipi2i2^i 的值,或者可以直接用快速幂计算,不了解快速幂的可以学一下。

psps:此处为了照顾大多数人就不用快速幂了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

const int MOD=1e9+7,maxn=1e6+5;

int n,a[1000005];
long long BS[1000005];

void init()
{
	BS[0]=1;
	for(int i=1;i<=maxn-1;i++)
	{
		BS[i]=(BS[i-1]%MOD*2)%MOD;
	}
}

int main()
{
	init();
	scanf("%d",&n);
	long long res=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		res=res%MOD+(a[i]%MOD*BS[n-1]%MOD)%MOD;
	}
	printf("%lld\n",res);
	return 0;
}

E.博学的学长

典型签到题,直接输出。 当然,你也可以去查ASCII码表。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int main() {
    printf("%c%c%c%c%c%c%c",67,72,70,89,89,68,83);
    return 0;
}

F.人生的抉择

题目看似复杂,其实原理很简单,用BA,BC向量的叉乘就可判断。 BAxBC(叉乘)=|BA|*|BC|*sinθ ,θ为两向量的夹角。(注意叉乘的顺序如果调换,判断原则也要变换)叉乘的计算为两向量交叉相乘再相减。

alt

夹角为90°时,向右转,叉乘的乘积大于0;

夹角为180°时,直走,叉乘乘积为0;

夹角为270°时,向左转,乘积小于0。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


int main() {
    long long xa,ya,xb,yb,xc,yc; //三个点,记得用long long
    scanf("%lld%lld%lld%lld%lld%lld",&xa,&ya,&xb,&yb,&xc,&yc);
    long long ans=(xa-xb)*(yc-yb)-(xc-xb)*(ya-yb);
    if(ans==0)printf("TOWARDS");
    else if(ans<0)printf("LEFT");
    else printf("RIGHT");
    return 0;
}

G.小锋卖瓜

简单的贪心思想

三种情况:

1.已经有了顾客需求种类的瓜,直接下一个;

2.没有顾客需要的瓜,容器还没有满,直接去进货,路费+1;

3.没有顾客需要的瓜且容器已满,这是需要扔掉某种瓜,这里就要用到贪心的思想,需要 扔掉最晚用到的一种瓜,才能使总的路费最少。

#include <stdio.h>

int a[100],have[100],vis[100][100],rem[100],num[100];

int main()
{
    int n,k,sum=0,total=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        vis[a[i]][rem[a[i]]]=i;//保存每种瓜出现的天数
        rem[a[i]]++;
//rem记录每种瓜已经出现几天,保证vis数组能按顺序存储a[i]种瓜都在哪一天出现
    }
    for(int i=1;i<=n;i++){
        vis[i][rem[i]]=0x3f3f3f3f;//将每种瓜的最后一位置为最大值
    }
    for(int i=1;i<=n;i++){
        num[a[i]]++; //记录当前循环a[i]种瓜已经出现几次
        if(have[a[i]])continue;//have记录容器中已有的瓜,1为有
        else if(total<k){  //第二种情况,直接去进货
            total++;   //容器已用空间+1
            have[a[i]]=1;   
        }else{
            int ma=-1,flag;  
            for(int j=1;j<=n;j++){
                if(have[j]&&vis[j][num[j]]>ma){
           //如果容器中有这种瓜,并且这种瓜出现的下一个天数大于当前最大值
  //因为上面已经将每种瓜的最后一位置为最大数,即后面已经不需要该种瓜,可以丢弃
                    ma=vis[j][num[j]],flag=j;//更新最大值,记录瓜的种类
                }
            }
            have[a[i]]=1,have[flag]=0;//丢弃瓜,买新瓜
        }
        sum++;//sum只在需要买瓜的时候+1
    }
    printf("%d",sum);
    return 0;
}


H.对称括号序列

考虑由符合题意得k对括号序列的构成方式:

f[k]f[k]代表由k对括号可以构成的合法对称括号序列的数量;

根据规则2,由k-1对括号序列在外侧增加一个括号,形如为 ( P ) ,其数量为 f[k1]f[k-1] 个;

根据规则3,由k-2对括号序列分别在左侧和右侧增加一个括号,形如 ( ) P ( ) ,其数量为 f[k2]f[k-2] 个;

综上,得到递推方程:f[i]=f[i1]+f[i2]f[i] = f[i-1] + f[i-2] ;

但是形如 (())(()) 之类的括号序列虽然是对称的,但是不能由题目给出的规则构造得到,所以不计入答案数量中,最后注意取模即可。

同时,这道题的结论也是斐波那契数列,直接手推前几项找规律也可以,前提是要读懂构造规则~~(读不懂建议remake)~~。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

const int MOD=1e9+7;

int t,n;
long long F[1000005];

int main()
{
	scanf("%d",&t);
	 
	F[1]=1,F[2]=2;
	for(int i=3;i<=1000004;i++) F[i]=(F[i-1]%MOD+F[i-2]%MOD)%MOD;
	while(t--){
	 	scanf("%d",&n);
	 	printf("%lld\n",F[n]);
	} 
	return 0;
}

ps:特别鸣谢杨哲聚聚的大力支持。