NOIP备赛总结——模板1

事先声明 :本文章是为了比赛前复习而用,营养量不是很高,若有大佬无意进入本蒟蒻的文章当中,还请键盘下留情,不要吐槽......

 第一篇文章总结一下前几天所打的一些模板题虽说是模板但也打了很久。。。

二分答案

       如其名,就是先把他的答案区间求出来,再二分,移动左右端点。

       妥妥的水题模板,就不上题目和代码le。

同余方程

    

  这个题,一开始就想着暴力枚举现在想想还真是蠢,其实只需要利用扩展欧几里得来求出他们的最大公约数,然后求出Ax+By=gcd(a,b)的解,然后利用一些奇奇怪怪的推得式子求出结果,具体代码如下:

long long exgcd(long long a,long long b,long long &x,long long &y){//需要有abxy四个变量 其实就是对着四个东西进行填表
	if(b==0){
		x=1,y=0;
		return a;//返回a
	}
	
		long long d=exgcd(b,a%b,x,y);//根据扩展欧几里得
		int t=x;x=y;y=t-a/b*y;//x y的更新
		return d;

}
int main(){
	long long a,b,d,x,y;
	cin >> a >> b;
	d=exgcd(a,b,x,y);
	cout << (x+b)%b;
	return 0;
	}

最小生成树

思路:

先对所有的边进行排序,小的放在前面大的放在后面。

对于n个点的树只需要n-1条边 。

特别注意在判断两个边有没有相连的时候是靠找他们的祖先是否相等,所以在连两条边的时候也是要把他们的祖先进行连接。

代码如下:

int  find(int x){
	if(f[x]==x)return x;
	else {
	f[x]=find(f[x]);//这一步很重要是为了保证这一条路的都把自己的最终祖先给标记了
	return f[x];
	}
}
void solov(){
	for(int i=1;i<=m;i++){
		f[tt[i].u]=tt[i].u;
		f[tt[i].v]=tt[i].v;
	}
	long long ans=0;
	int k=1;
	while(k<=n-1){//n个点只需建立n-1条边
		int u=q.top().u,v=q.top().v,w=q.top().w;
		int fau=find(u),fav=find(v);
		if(fau!=fav){//利用f数组来存自己的最终祖先目的是为了判断这两个点有没有连通,如果有就加上价值然后把他的祖先进行更改
			ans+=w;
			f[fau]=fav;//注意这里是把这两个的祖先连起来
			k++;//边数加一
			}
		q.pop();
	}
	cout <<ans <<endl;
}

快速幂

思路:

把指数利用二进制拆开 然后对于二进制的每个位上的数来说都是前一个的平方 这样就可以只用log(n

)的时间复杂度就可以写完。

特别注意 1.在乘的时候取模 2.在乘的时候还是会爆int所以记得用loonglong3.注意输出格式

代码如下:

long long b,p,k;
    cin >> b >> p >> k ;
	long long cntb=b,cntp=p,cntk=k;
    if(p==0){
        cout <<"1" <<endl;
	return 0;
    }
    long long ans=1;
    long long t=b;
    while(p!=0){//利用二进制拆分指数然后累乘
    	if(p&1==1)ans=(ans*t)%k;
	    p=p >> 1;
 	    t=(t*t)%k;//指数试增长所以这里是t*t
    }

树状数组

动态区间查询

思路:

利用二进制不难发现可以通过二进制的每一位来存值,存的话就是利用一种类似于前缀和的方法。

主要通过一个lowbit来执行 取二进制的最后一位的值

#define lowbit(x) (x&(-x))

其他什么的都显而易见

代码如下:

void add_number(int i,int x){
	while(i<=n){
		tree_number[i]+=x;
		i=i+lowbit(i);
		}
}
long long up_date(int i){
	long long ans=0;
	while(i!=0){
		ans+=tree_number[i];
		i=i-lowbit(i);
		}
	return ans;
}
int main(){
        freopen("treeArray.in","r",stdin);
	freopen("treeArray.out","w",stdout);
	cin >> n >> q;
	int x;
	for(int i=1;i<=n;i++){
	    scanf("%d",&x);
	    add_number(i,x);
		}
	int t,l,r;
    for(int i=1;i<=q;i++){
		scanf("%d%d%d",&t,&l,&r);
		if(t==1)add_number(l,r);
		else cout << up_date(r)-up_date(l-1) <<endl;
	}
return 0;
}		

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值