关于学长太善良出了一道朴素差分题。
题目大意:
给你一个n和m,分别表示区间的长度和操作的次数,然后m次询问每次有三个数l,r,c,表示区间 l 到r 的草长c单位的长度,问最后每个位置草长度为多少
这一题是差分的模板,不了解的话可以看这篇博客戳我查看
代码如下
#include<stdio.h>
int a[100005],b[100005];
int main(){
int n,m;
scanf("%d%d",&n,&m);
int l,r,c;
while(m--){
scanf("%d%d%d",&l,&r,&c);
b[l]+=c;
b[r+1]-=c;
}
for(int i=1;i<=n;i++){
b[i]+=b[i-1];
printf("%d ",b[i]);
}
return 0;
}
派小星点星
给你一个n和m,分别表示区间的长度和操作的次数,之后输入n个整数,表示数组里的数,然后m次询问每次有三个数l,r,表示询问区间 l 到r 的总数是多少
同上题一样这是前缀和的模板,暴力做法会TLE,上面那篇博客也有前缀和的讲解
代码如下
#include<stdio.h>
int a[200005],b[200005];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
b[i]=b[i-1]+a[i];
}
int q;
scanf("%d",&q);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",b[r]-b[l-1]);
}
return 0;
}
重生之我在异世界学差分
和第一道题一模一样,但是这道题不用差分做会超时,这里不再罗嗦了
最大连续子段的异或和
题目大意:
给出一个正整数序列,求异或和最大的连续子段和。
这道题数组很小,只有100,所以我们可以把每个区间都算一遍,代码中 i 相当于是左端点,j相当于是右端点,可以知道两重for循环可以不重不漏的把所有区间都算完。
代码如下:
#include<stdio.h>
int t[1005];
int main(){
int n,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&t[i]);
for(int i=1;i<=n;i++)
{
int sum=0; //将sum设为0
for(int j=i;j<=n;j++)
{
sum^=t[j];
if(sum>ans) ans=sum; //每异或一次,就和答案取最大值
}
}
printf("%d\n",ans);
return 0;
}
肥波纳妾
题目大意
第一行是询问的次数t,接下来每行一个整数n表示上面这个序列的第n个数是多少
从序列中我们可以发现第n个数是第n-1个数和第n-2个数的和,所以把前两个数输入进去,接下来的数都可以推出来
#include<stdio.h>
int a[50];
int main(){
int t,n,i;
a[1]=1,a[2]=1;
scanf("%d",&t);
for(i=3;i<=40;i++){
a[i]=a[i-1]+a[i-2];
}
while(t--){
scanf("%d",&n);
printf("%d\n",a[n]);
}
return 0;
}
杨辉三角(Easy)
题目大意:
如果我们按杨辉三角从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, …
给定一个正整数 n ,请你输出数列中第一次出现 n 是在第几个数?
如果把杨辉三角画成这样,我们可以发现一个数是它上方和上方左边的和,如果在边界的话,它就是1
由此我们可以处理出前100行然后一行一行的找答案
代码如下:
#include<stdio.h>
int a[105][105];
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=101;i++)
{
for(int k=1;k<=i;k++)
{
if(k==1||k==i) a[i][k]=1; //表示在边界
else a[i][k]=a[i-1][k-1]+a[i-1][k];
}
}
while(t--)
{
int n;
scanf("%d",&n);
int num = 0;
int flag = 0;
for(int i=1;i<=101;i++)
{
for(int k=1;k<=i;k++)
{
num ++ ;
if(a[i][k]==n) //表示我们找到了答案
{
flag = 1;
break;
}
}
if(flag)break;
}
printf("%d\n",num);
}
return 0;
}
取石子(pro plus max 版)
题目大意:
给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
这道题涉及到了位运算,代码简单但思维难度较大,证明过程水平有限,大家用心看一下
首先结论: 如果初始所有值的异或结果不为0,则先手必胜,反之必败
我们可以知道0^ 0 ^… ^ 0 ^ 0=0
然后有两个推论
当序列异或的结果不为0的时候,我们必然有种方式拿走石子使异或结果为0
当序列异或的结果为0的时候,我们无论怎么拿走石子异或结果都不会再为0
证明如下
首先当a[1] ^ a[2] ^ … ^ a[n] = x != 0 时
记x的二进制表示中最高位的1是第k位,则肯定存在一个a[i]的第k位为1(因为要使两个数异或结 果 为1,必然要有一个1)
可知a[i]^x < a[i](因为x的最高位的1在k,第k位都为1,因此异或后第k为0,比k位低的异或结果不 管是怎么样的,最终结果肯定比a[i])
因此可以把a[i]变成a[i]^x
这样结果会变成a[1] ^ a[2] ^ … ^ a[i] ^ x ^ … ^ a[n] = 0
当a[1] ^ a[2] ^ … ^ a[n]= 0 (式1)时
当从任意一堆中拿走任何数量的石子后,异或结果肯定不等于0
反证法证明:
假设从任意一堆a[i]中拿走任何数量的石子后(a[i]变成a[t]),异或结果等于0,则a[1] ^ a[2] ^ … ^ a[t] ^ … a[n] = 0(式2)
则 式1^式2 = 0 -> a[t] ^ a[i] = 0 -> a[t] = a[i] , 这与a[i] > a[t]矛盾,因此假设不成立
所以当序列异或结果不为0时,先手可以让异或结果变成0,后手只能让异或结果不为0,然后如此往复,最后一定是先手到达 0^ 0 ^… ^ 0 ^ 0=0,的状态,也就是胜利,反之,先手必败
代码如下:
#include <stdio.h>
int main()
{
int res=0,n=0;
scanf("%d",&n);
while(n--)
{
int x;
scanf("%d",&x);
res ^= x;
}
if(res) printf("Yes");
else printf("No");
return 0;
}
重生之我在异世界遇到差分。
题目大意:
给你长度为n的路,每个点都有一个怪物,血量是ai,你可以对某个区间的所有怪物造成1点伤害,但是如果这个点怪物血量为0,还对这个点造成伤害的话是不允许的,问你最少进行多少次操作可以击败所有怪物。
这道题我们可以这样想,
1.如果ai>ai-1,那么答案只用加上ai-ai-1就行了,因为我们完全可以在减ai-1的血量的时候顺便再把ai算上,最后只需要多算它们两个的差就行了。
2.如果ai<=ai-1,那么答案就不用更新,因为我们在减ai-1的时候就顺带着可以把ai的血量减完了
代码如下:
#include<stdio.h>
int a[2000005];
int main(){
int n,sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]-a[i-1]>0) sum+=a[i]-a[i-1];
}
printf("%d",sum);
}