调查员三宝之朋友:

题意:

求有多少个连续的数段,这些数段中的全部数之和为m

双指针做法:

用i,j代表区间的左右端点,sum代表[i,j]这个区间所有数之和

当sum小于目标值M时,将右端点右移(j++),sum会变大

当sum大于目标值M时,将左端点右移(i++),sum会变小

在双指针移动的过程中,如果有sum==M的情况ans+1。

因为两个指针都是单调向右移动,也只扫一遍,可以证明时间复杂度为O(n)

左端点大于m/2时即可停止,因为只要长度为2的连续序列和就一定大于m

#include<stdio.h>

int main()
{
	int m, ans = 0, sum = 3;
	scanf("%d", &m);
	for (int i = 1, j = 2; i <= m / 2;)
	{
		if (sum == m)
		{
			ans ++ ;
			sum -= i;
			i ++ ;
		}
		else if (sum < m)
		{
			j ++ ;
			sum += j;
		}
		else
		{
			sum -= i;
			i ++ ;
		}
	}
	printf("%d", ans);
	return 0;
}

调查员三宝之撬棍:

分析:

一个二进制数变为原来的17倍,相当于这个数乘以16再加上原来的数

二进制下,数的末尾添加一个零,相当于这个数乘以2,所以将这个数的末尾加上4个0,再加上原来的数

N最大是1000位,可以用高精加来进行计算(用数组来模拟加法)

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

int main()
{
	char s[1100] = {0};
	scanf("%s", s);
	int n = strlen(s);
	int t1[1100] = {0}, t2[1100] = {0}; // t1是原本的数,t2是原来的数乘以16
	for (int i = 0; i < n; i ++ )
	{
		t2[i + 4] = t1[i] = s[n - i - 1] - '0';
	}
	n += 4;
	for (int i = 0; i < n; i ++ )
	{
		t2[i] += t1[i];
		if (t2[i] > 1)
		{
			t2[i] -= 2;
			t2[i + 1] += 1;
		}
	}
	while (t2[n] > 1)
	{
		n ++ ;
	}
	for (int i = n - 1; i >= 0; i -- )	
		printf("%d", t2[i]);
	return 0;
}

调查员三宝之旧印:

分析:

x <= y <= z,显然七个数中,最小的是x,次小的是y,最大的是x+y+z

将7个数排序后,依次输出最小的,次小的,最大的减去最小的和次小的

#include<stdio.h>

int main()
{
	int a[10];
	for (int i = 1; i <= 7; i ++ )
	{
		scanf("%d", &a[i]);
	}
	for (int i = 1; i <= 7; i ++ )
	{
		for (int j = i + 1; j <= 7; j ++ )
		{
			if (a[i] > a[j])
			{
				int t = a[i];
				a[i] = a[j];
				a[j] = t;
			}
		}
	}
	printf("%d %d %d", a[1], a[2], a[7] - a[1] - a[2]);
	return 0;
}

签到题:

分析:

任意两个相邻的正整数的最大公约数为1

这样的话我们最多只需要进行两次操作(对第n个数和第n-1个数进行操作)就可以让整个数组的最大公约数为1.

接着分情况判断就行:

1.不需要操作,成本为0

2.对第n个数进行操作,成本为1

3.对第n-1个数进行操作,成本为2

4.对第n个数和第n-1个数进行操作,成本为3

#include<stdio.h>

int a[25];
int n;

int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ )
	{
		scanf("%d", &a[i]);
	}
	int g = a[1];
	for (int i = 2; i <= n; i ++ )
	{
		g = gcd(g, a[i]);
	}
	int ans = 0;
	if (g != 1)
	{
		if (gcd(g, n) == 1)	ans = 1;
		else if (gcd(g, n - 1) == 1)	ans = 2;
		else	ans = 3;
	}
	printf("%d", ans);
	return 0;
}

签到题·真:

输出就行

#include<stdio.h>

int main()
{
    printf("\"a %% b = c\"");
    return 0;
}

最大值:

分析:

如果火技能的数量与冰技能的数量相等,则除初始伤害最小的技能外,所有技能的伤害加倍。

否则,设k为两种技能数量的最小值,然后将每种技能中初始伤害最大的k个技能的伤害加倍。

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

int t[1005], fire[1005], ice[1005], fl, il;
long long ans;

void sort(int a[], int n)
{
	for (int i = 1; i <= n; i ++ )
	{
		for (int j = i + 1; j <= n; j ++ )
		{
			if (a[i] < a[j])
			{
				int t = a[i];
				a[i] = a[j];
				a[j] = t;
			}
		}
	}
}

int main()
{
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ )	scanf("%d", &t[i]);
	for (int i = 1; i <= n; i ++ )
	{
		int x;
		scanf("%d", &x);
		if (t[i])
		{
			ice[++il] = x;
		}
		else
		{
			fire[++fl] = x;
		}
		ans += x;
	}
	sort(ice, il);
	sort(fire, fl);
	int temp = il < fl ? il : fl;
	for (int i = 1; i <= temp; i ++ )
	{
		ans += fire[i] + ice[i];
	}
	if (fl == il)
	{
		ans -= ice[il] < fire[fl] ? ice[il] : fire[fl];
	}
	printf("%lld", ans);
	return 0;
}

棋子反转:

题意:

读入表示棋子状态的字符串,要把棋子都翻到1。翻转有一定的规则,如果你要翻第i枚棋子,必须把1~i枚都翻转。问怎么翻才能用最少的次数得到全部为1的棋子序列。

分析:

从左往右扫,如果这个棋子与下个棋子状态不同,就说明要翻一次。最后还得判断最后一个是不是0,如果是0还要再翻一次,因为题目说要全部正面朝上,就是全部为1,最后一位为0就说明翻完后全是0,还要再翻一次。

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

char s[1000005];

int main()
{
	scanf("%s", s);
	int ans = 0;
	int n = strlen(s);
	for (int i = 0; i < n - 1; i ++ )
	{
		if (s[i] != s[i + 1])
			ans ++ ;
	}
	if (s[n - 1] == '0')	ans ++ ;
	printf("%d", ans);
	return 0;
}

神之天平:

分析:

用i,j分别表示左端点和右端点,suml,sumr表示目前左托盘和右托盘的灵魂重量。

ans为答案,res为距离上一次天平平衡,左右托盘新增灵魂数量

两个指针相遇前,进行循环,每次循环进行判断:

1.suml<sumr

将指针i右移,suml加上w[i]

2.suml>sumr

将指针j左移,sumr加上w[j]

3.suml=sumr

更新ans和res,且将指针i右移,suml加上w[i]或将指针j左移,sumr加上w[j]

#include<stdio.h>

int w[100005];
int n;
int ans;

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ )
	{
		scanf("%d", &w[i]);
	}
	long long suml = w[1], sumr = w[n], res = 2;
	for (int i = 1, j = n; i < j; )
	{
		while (suml < sumr && i < j)
		{
			i ++ ;
			suml += w[i];
			res ++ ;
		}
		while (suml > sumr && i < j)
		{
			j -- ;
			sumr += w[j];
			res ++ ;
		}
		if (suml == sumr)
		{
			i ++ ;
			suml += w[i];
			ans += res;
			res = 1;
		}
	}
	printf("%d\n", ans);
	return 0;
}