比赛:牛客小白月月赛39
本人小记+代码:
A题:(签到)
- 向量(x,y)+(x0,y0)=(x+x0,y+y0)
- 向量平行条件:(满足其一即可,不要混淆在一起)
1、a=λb(λ!=0),则a∥b。
2、设a(x1,y1)、b(x2,y2),若x1y2=y1x2,则a∥b
C题:
看视频讲解:
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
int n;scanf("%d",&n);
int A=0,B=0,a,b;
ll ans=0;
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a,&b);
ans+=max(0,min(a,b)-max(A,B)+(A!=B));
A=a,B=b;
}
printf("%lld\n",ans);
return 0;
}
/*
我的理解:
细细琢磨琢磨这三句话:
a b序列分别遵循从小到大,且初A=0,b=0;
情况2:当A=at时,让B直接加到与bt相等
情况3:当B=bt时,让A直接加到与at相等
i从(1,n)遍历,
只需考虑当前A变a[i],B变b[i]后,ans需要加多少
为何:
若a[i],b[i]满足情况2或3,那A和B最后铁定要变成A=a[i],b[i];
若不满足,考虑情况4:(A,B)其一加1,
加多少次才会满足情况2或3呢,不清楚,那为何不直接A=a[i],b[i];
为何可以从1逐步遍历到n呢?
还是因为那三句话:
A和B只能逐步变大,恰数列a,b也是从小到大。
比如:
当前A=3,B=9。怎么得到A=3,B=9呢,肯定源于比它小的a[i]和b[i]得到
若A,B想再变大,肯定要遍历不能小于当前A,B的a[i]和b[i].
因此题意转变为:
当A,B变成a[i]和b[i]时,ans需要加多少次
A B
a[i] b[i]
肯定A<=a[i],B<=b[i]
不确定:A和B,a[i]和b[i]的大小;
不确定:A和b[i],B和a[i]的大小;即max(A,B)和min(a[i],b[i])大小不确定
A-->a[i]
B-->b[i]
公共部分为:[max(A,B),min(a[i],b[i])]
因此:ans+=max((max(A,B),min(a[i],b[i])+ (A!=B)),0);
*/
G题:
看视频讲解(讲的不是很明白,本人对树状数组理解有欠缺,代码正确,但不太明白)
#include<bits/stdc++.h>
using namespace std;
const int N=3e6;
const int maxn=3e6+110;
int res[maxn],tr[maxn];
bool book[maxn];
int p[maxn],pmin[maxn],cnt;
/*
book,p,cnt为欧拉素数筛使用
pmin[i]表示i的最小质因数为pmin[i]
算了,下面的理解也应该不对
Query(k)表示1~N中<=k的质数的个数
可利用树状数所构造的数据结构求前缀和[1,x]的前缀和,即Query(x).
该前缀和为1~N中最小质因数为2的个数 + 1~N中最小质因数为3个数 + ...
*/
struct Node{
int n,k,id;
bool operator<(const Node &b)const
{
if(n==b.n) return k<b.k;
else return n<b.n;
}
}q[maxn];
void Get_prime()
{
cnt=0;book[1]=1;
for(int i=2;i<=N;i++)
{
if(!book[i])
p[++cnt]=i,pmin[i]=i;
for(int j=1;j<=cnt&&p[j]<=N/i;j++)
{
book[i*p[j]]=1;
pmin[i*p[j]]=p[j];
if(i%p[j]==0) break;
}
}
}
int lowbit(int x){ return x&(-x);}
void add(int x,int d)
{
while(x<=N)
{
tr[x]+=d;
x+=lowbit(x);
}
}
int Query(int x)
{
int ans=0;
while(x>0)
{
ans+=tr[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
Get_prime();
int m;scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int n,k;scanf("%d %d",&n,&k);
q[i]={n,k,i};
}
sort(q+1,q+1+m);//按照n从小到大排序
int p=1;
for(int i=1;i<=m;i++)
{
while(p<q[i].n)
add(pmin[++p],1);
res[q[i].id]=q[i].n-1-Query(q[i].k-1);
//-1是1~n中1不算
//Query(k)求的是在[1,N]中最小质因子>=k的数有多少个
//tr[x]表示区间[x-lowbit(x)+1,x]
}
for(int i=1;i<=m;i++)
printf("%d\n",res[i]);
return 0;
}
/*
1
8 2
for(int i=1;i<=10;i++)
printf("^^^%d\n",Query(i));
*/
H题:
视频讲解很详细
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+110;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll p[N],s[N],pre[N],suf[N];
int main()
{
int n,d;scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&p[i]);
s[i]=p[i];
}
pre[0]=0;
for(int i=1;i<=n;i++)
{
d=p[i];
pre[i]+=pre[i-1]+d;
p[i+1]=max(0ll,p[i+1]-d);
p[i+2]=max(0ll,p[i+2]-d);
}
suf[n+1]=0;
for(int i=n;i>=1;i--)
{
d=s[i];
suf[i]+=suf[i+1]+d;
s[i-1]=max(0ll,s[i-1]-d);
s[i-2]=max(0ll,s[i-2]-d);
}
if(n<=2)
printf("0\n");
else
{
ll ans=INF;
for(int i=2;i<=n;i++)
ans=min(ans,pre[i-2]+suf[i+1]);
printf("%lld\n",ans);
}
return 0;
}