心得吧

从开始到集训已经持续了有七八天了,大大小小也是学到了很多东西,当然也得到了很多不懂的东西,明白了差距,不说废话了,总结一下最近学到的东西吧,从开始的贪心,二分,尺取,以及单调栈,单调队列,到kmp,数论的东西,欧拉算法,矩阵的快速幂,快速素数筛,逆元等等。
就从今天的开始吧 :
gcd模板:
int gcd( int a ,int b)
{
return b==0? a :gcd( b,a%b);
}
这个是现阶段我最熟悉的gcd了,做了两道题目吧。
链接1:http://acm.hdu.edu.cn/showproblem.php?pid=5974
对于这道题,大概是:给你a和b,让你求出X和Y,使得X + Y = a lcm(x,y) = b,令gcd(x,y)=g,那么
g * k1 = x;
g * k2 = y;
因为g是最大的公因数,所以k1和k2是互质的,所以k1+k2和k1k2 也是互质的,推出
=> g
k1k2 = b
=> g
k1 + g * k2 = a;
整理后得到 g*(k1k2)=b;
g
(k1+k2)=a
所以就是gcd(a,b)=g;最后这道题目的关键就解出来了 就是让你推出来
gcd(a,b)=gcd(x,y) 所以现在的问题就是解方程了,做的时候没想到,有点复杂,其实用笔推一下,就是把x换成y 带到第二个方程就能解出来了。

#include <iostream>
#include <math.h>
#define ll long long 
using namespace std;
ll x,y,a,b,a_c,bb,g,dt,t;
int gcd(ll a,ll b)
{
	return b==0?a:gcd(b,a%b);
}
int main()
{
	int flag;
	while(scanf("%lld %lld",&a,&b)!=EOF)
	{
		flag=0;
		g=gcd(a,b);
		a_c=b*g;
		dt=a*a-4*a_c;
		if(dt<0)
		{
        printf("No Solution\n");
        continue;
        }
        t=sqrt(dt);
        if(t*t!=dt)
        {
        flag=1;
        }
        ll ans1,ans2;
        ans1=a+t;
        ans2=a-t;
        if(!flag)
        printf("%lld %lld\n",ans2/2,ans1/2);
        else
        printf("No Solution\n");
	}
	return 0;
}

第二道题目:告诉你a,b gcd(a,c)=b,并且c!=b,求出最小的c
题目链接https://vjudge.net/contest/316484#problem/B

#include <iostream>
using namespace std;
int a,b,c;
int gcd(int a,int b)
{
	return b==0? a:gcd(b,a%b);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
  {
	  scanf("%d %d",&a,&b);
	  c=2*b;
	 while(gcd(a,c)!=b)
	 {
	 	c+=b;
	 }
	 printf("%d\n",c);
  }
  return 0;
}

在此之后就是欧拉函数了,欧拉函数就是返回与n互质数的个数 比如 euler(9)=6,eluer(1)=1与9互质的数(不包括本身)有 1,2,4,5,7,8,这几天做题的板子,用的有两个:

 ll euler(ll x)
{
	ll ret=1;
	for(ll i=2;i*i<=x;i++)
	{
		if(x%i==0)
		{
			x/=i; ret*=(i-1);
			while(x%i==0)
			{
		      x/=i; ret*=i;
			}
		}
	}
	if(x>1) ret*=x-1;
	return ret;
}
   这个板子不知道为什么不能用,题目写的下面了,还有一个板子;
   int euler(int n)
   {
      int ret=1,i;
      for(i=2;i*i<=n;i++)
      {
       if(n%i==0)
       {
       n/=i; ret*=(i-1);
       while(n%i==0)
       {
         n/=i;
         ret*=i;
        }
        if(n>1) ret*=n-1;
        return ret;
    }    

欧拉函数的题目https://vjudge.net/contest/316484#problem/C
https://vjudge.net/contest/316484#problem/H 这个不能用第一个板子,题目错了。
https://vjudge.net/contest/316484#problem/G
卡特兰数是一种排列组合什么的吧,这个见到再弄,是因为这个数才略懂了什么是逆元,说一下什么是逆元吧,昨天晚上看见了一篇博客说的比较清楚;
为什么要有逆元,因为要计算(a/b)%mod时候,(a/b)%mod !=(a%mod)/(b%mod),所以要把除法变成乘法,设 c是b的逆元 : b*c≡1(mod m); 则(a/b)%m=(a *c)mod(m),即a/b的模=a乘b的逆元的模;
下面说一下 我目前会的求一个数的逆元:
费马小定理
如果p是质数,并且gcd(a,p)=1,那么a^(p-1)≡1(mod p)
也就是a^(p-1)%p=1,带换一下 式子变成了 a * a^(p-2)%p=1,s所以就是a的逆元就是
a^(p-2);有一个题目
利用通项公式求出h(0)=1,然后打表存储1-1000000的卡特兰数,注意计算逆元。 因为1e9+7是质数,所以(n+1)与mod一定有逆元,n+1与mod的逆元是 ( (n+1)^(mod-2) )%mod.
题目链接:https://vjudge.net/contest/316484#problem/I

#include <iostream>//p为质数,a^p=1(mod p),gcd(a,p)=1,费马小定理,快速幂 
#include <cstring>
#define ll long long
const int mod=1e9+7;
using namespace std;
ll h[1000005];
ll t,x;
int quick_niyuan(ll a,ll b)//a^b
{
	int ans=1;
	a%=mod;
	while(b)
	{
		if(b&1) ans=ans*a%mod,b--;
		b>>=1;
		a=a*a%mod;
	}
	return ans%mod;
}
int main()
{
	scanf("%lld",&t);
	h[0]=1;
	for(ll i=1;i<=1000000;i++)
	 h[i]=((h[i-1]*(4*i-2)%mod)*quick_niyuan(i+1,mod-2))%mod;//此时i+1就是a 
	ll k=0;
	while(t--)
	{
		scanf("%lld",&x);
		printf("Case #%d:\n",++k);
		printf("%lld\n",h[x]);
	}
	return 0;
}

这个就是我目前所了解的逆元!
之后就是矩阵快速幂了,这个东西也刚刚接触,不太熟练,我目前认为的矩阵快速幂的就是给出一个递推关系式,然后你观察这个式子就能发现递推的规律,这个关系就是一个几阶的矩阵吧,然后就是递推了,理解不深刻!
做了两个很简单的矩阵快速幂的题目:
题目链接:https://vjudge.net/contest/316484#problem/K

#include <iostream>
#define ll long long
using namespace std;
ll A,B,n;
struct node
{
	ll m[2][2];
};
 node ans,a;  //ans是最后输出的答案矩阵,而a是推出来的递推矩阵,注意矩阵ans刚开始要赋值为单位矩阵!
 node mul(node x,node y)
 {
 	 node c;
 	 for(ll i=0;i<2;i++)
 	 for(ll j=0;j<2;j++)
	   c.m[i][j]=0; 
 	 for(ll i=0;i<2;i++)
	 for(ll j=0;j<2;j++)
	 for(ll k=0;k<2;k++) 	
	  c.m[i][j]=(c.m[i][j]+x.m[i][k]*y.m[k][j]%7)%7;
	  return c;
 }
node quick_juzhen(node x,ll t) //矩阵快速幂的板子
{
	while(t)
	{
		if(t&1) ans=mul(ans,x),t--;
		 t>>=1;
		x=mul(x,x); 
	}
	return ans;
}
int main()
{
   while(scanf("%lld %lld %lld",&A,&B,&n))
   {
   	 if(A==0&&B==0&n==0) break;
   	 a.m[0][0]=A,a.m[0][1]=B,a.m[1][0]=1,a.m[1][1]=0;
   	 ans.m[0][0]=1,ans.m[1][1]=1;
   	 ans.m[0][1]=0,ans.m[1][0]=0;
   	 //f[1]=1,f[2]=1;
   	 if(n<=2)
   	 {
   	    printf("1\n");
		continue;	
	 }
	 n-=2;
	 quick_juzhen(a,n);
	 printf("%lld\n",(ans.m[0][0]+ans.m[0][1])%7);
   }
   return 0;
} 

另一道题目的链接:https://vjudge.net/contest/316484#problem/L
上代码:

#include <iostream>
#define ll long long
using namespace std;
const int mod=9973;
struct node
{
	ll m[15][15];
};
ll t,n,k;
node ans,a;
node mul(node x,node y)
{
	node c;
	for(ll i=0;i<n;i++)
	for(ll j=0;j<n;j++)
	 {
	 	c.m[i][j]=0;
	 	for(ll k=0;k<n;k++)
	 	c.m[i][j]=(c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod)%mod;
	 }
	 return c;
}
node quick_pow(node x,ll b)
{
	while(b)
	{
		if(b&1) ans=mul(ans,x),b--;
		b>>=1;
		x=mul(x,x);
	}
	return ans;
}
int main()
{
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld %lld",&n,&k);
		for(ll i=0;i<n;i++)
		for(ll j=0;j<n;j++)
		scanf("%lld",&a.m[i][j]);
		for(ll i=0;i<n;i++)
		{
			for(ll j=0;j<n;j++)
			{
				if(i==j) ans.m[i][j]=1;
				else ans.m[i][j]=0;
			}
		}
		quick_pow(a,k);
		ll sum=0;
		for(ll i=0;i<n;i++)
		{
			for(ll j=0;j<n;j++)
			 if(i==j)
			 {
			 	sum+=ans.m[i][j]%mod;
			 }
		}
		printf("%lld\n",sum%mod);
	}
	return 0;
}

以上就是从八月开始到八月三号15.10十分了解到的数论;end
再补充一道最近看到的一道题目:是关于费马小定理; a^(p-1)%p=1; gcd(a,p)=1,p是质数
题目连接:https://vjudge.net/contest/316484#problem/O
贴上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int mod=1e9+7,N=1e5+5;
char a[N];
 
LL quick_mod(LL a,LL p)          //快速幂 (快速幂利用了二分思想和秦九昭算法)
{
    LL ans=1;
    while(p)
    {
        if(p&1)
        ans=ans*a%mod;
        a=a*a%mod;
        p>>=1;
    }
    return ans;
}
 
int main()
{
    while(~scanf("%s",a))
    {
        int len=strlen(a);
        LL ans=0;
        for(int i=0;i<len;i++)
        {
            ans=(ans*10+a[i]-'0')%(mod-1); //求余mod-1 需要特别注意,100%13这个例子;
        }
        ans=(ans-1+mod)%mod;
        printf("%lld\n",quick_mod(2,ans));
    }
    return 0;
}

``
附上博客:https://blog.csdn.net/strangedbly/article/details/50996908
 				           
 				           
 				           
 				
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值