数学の入门到入土 第4天

接着昨晚一个没AC的题 Recursive sequence 矩阵快速幂&递推
给我们递推公式 F(n)=F(n-1)+F(n-2)*2+n4 求第n项 对mod=2147493647余
其实就是一个水题吧,因为之前我用过矩阵快速幂求FIB(n)%mod的板子
但是不知道具体原理 QAQ 线代上学期考了不多不少刚好60

矩阵学习&矩阵快速幂 贴一手(sdl
简单的说 设矩阵A F (如果单纯的求Ak 就不细讲了)
存在递推关系式 F(n)=pF(n-1)+qF(n-2)
设置初始矩阵 【F(n) F(n-1) F(n-2)】 (线代太弱了,我还是习惯于这样子存) 1M的矩阵 需要构造一个M1的矩阵 做矩阵乘法得到 【F(n+1) F(n) F(n-1)】 那么显然每乘一次递推矩阵A 就可以得到下一个状态

    • 就是构造递推矩阵有点麻烦 其他的 基本上很好理解
  • – ------ 应该还是很好理解吧 就是自己推一下初始矩阵 以及递推矩阵
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
inline ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}
const int mod = 2147493647;
int aa,bb,n;
struct Matrix {
  int a[9][9];
  Matrix() { memset(a, 0, sizeof a); }
  Matrix operator*(const Matrix &b) const {
    Matrix res;
    for (int i = 1; i <= 8; ++i)
      for (int j = 1; j <= 8; ++j)
        for (int k = 1; k <= 8; ++k)
          res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]) % mod;
    return res;
  }
} ans, base;

void init() {
base.a[1][1]=1;
base.a[1][2]=1;
base.a[1][3]=0;
base.a[1][4]=0;
base.a[1][5]=0;
base.a[1][6]=0;
base.a[1][7]=0;
base.a[1][8]=0;

base.a[2][1]=2;
base.a[2][2]=0;
base.a[2][3]=1;
base.a[2][4]=0;
base.a[2][5]=0;
base.a[2][6]=0;
base.a[2][7]=0;
base.a[2][8]=0;

base.a[3][1]=0;
base.a[3][2]=0;
base.a[3][3]=0;
base.a[3][4]=0;
base.a[3][5]=0;
base.a[3][6]=0;
base.a[3][7]=0;
base.a[3][8]=0;

base.a[4][1]=1;
base.a[4][2]=0;
base.a[4][3]=0;
base.a[4][4]=1;
base.a[4][5]=0;
base.a[4][6]=0;
base.a[4][7]=0;
base.a[4][8]=0;

base.a[5][1]=4;
base.a[5][2]=0;
base.a[5][3]=0;
base.a[5][4]=4;
base.a[5][5]=1;
base.a[5][6]=0;
base.a[5][7]=0;
base.a[5][8]=0;

base.a[6][1]=6;
base.a[6][2]=0;
base.a[6][3]=0;
base.a[6][4]=6;
base.a[6][5]=3;
base.a[6][6]=1;
base.a[6][7]=0;
base.a[6][8]=0;

base.a[7][1]=4;
base.a[7][2]=0;
base.a[7][3]=0;
base.a[7][4]=4;
base.a[7][5]=3;
base.a[7][6]=2;
base.a[7][7]=1;
base.a[7][8]=0;

base.a[8][1]=1;
base.a[8][2]=0;
base.a[8][3]=0;
base.a[8][4]=1;
base.a[8][5]=1;
base.a[8][6]=1;
base.a[8][7]=1;
base.a[8][8]=1;



  ans.a[1][2] =bb;
  ans.a[1][3] =aa;  //初始值
  ans.a[1][1] =aa*2+bb+81;
  ans.a[1][4]=81;
  ans.a[1][5]=27;
  ans.a[1][6]=9;
  ans.a[1][7]=3;
  ans.a[1][8]=1;
}
/*
[p  1

 q  0]*/

void qpow(int b) {
  while (b) {
    if (b & 1) ans = ans * base;
    base = base * base;
    b >>= 1;
  }
}

signed main() {
  ll t=read();

  while(t--){
  n=read();
  aa=read();
  bb=read();
  if(n==1){
    printf("%lld\n",aa%mod);
  continue;
  }
  if(n==2){
    printf("%lld\n",bb%mod);
  continue;
  }
  init();
  qpow(n-3);
printf("%lld\n",ans.a[1][1]%mod);

}
return 0;

}

理解了原理后感觉也蛮简单的(或许是错觉) 贴一个模板题
数列加速 洛谷

不是很明显的递推关系式&矩阵加速
给你p=a+b q=a*b 求 (an +bn ) %264
QAQ原来模264 让它自然溢出就好了 (长见识了
我们的目的是递推F(n)= (an +bn ) 那么就尝试拿F(n-1) F(n-2) 去凑吧 (我凑了一会

递推关系式找到了以后 写一下初始矩阵以及递推矩阵就好了

#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll unsigned long long
#define int unsigned long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
inline ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}


ll aa,bb,n,p,q,mod=1;
struct Matrix {
  int a[9][9];
  Matrix() { memset(a, 0, sizeof a); }
  Matrix operator*(const Matrix &b) const {
    Matrix res;
    for (int i = 1; i <= 3; ++i)
      for (int j = 1; j <= 3; ++j)
        for (int k = 1; k <= 3; ++k)
          res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]);
    return res;
  }
} ans, base;

void init() {
base.a[1][1]=p;
base.a[1][2]=1;
base.a[1][3]=0;

base.a[2][1]=-q;
base.a[2][2]=0;
base.a[2][3]=1;



base.a[3][1]=0;
base.a[3][2]=0;
base.a[3][3]=0;


  ans.a[1][2] =p*p-2*q;
  ans.a[1][3] =p;  //初始值
  ans.a[1][1] =p*ans.a[1][2]-q*ans.a[1][3];

}
/*
[p  1

 q  0]*/

void qpow(int b) {
  while (b) {
    if (b & 1) ans = ans * base;
    base = base * base;
    b >>= 1;
  }
}

signed main() {
  ll t=read();
  ll add=0;
  while(t--){
  p=read();
  q=read();

  n=read();
  add++;
  printf("Case %lld: ",add);
  if(n==0){
    printf("2\n");
  continue;
  }
  if(n==1){
    printf("%llu\n",p);
  continue;
  }
 if(n==2){
    printf("%llu\n",(p*p-2*q));
    continue;
 }

  init();
  qpow(n-3);
printf("%llu\n",ans.a[1][1]);

}
return 0;

}

在这里插入图片描述
(矩阵加速真心快

2013年长沙邀请赛 &矩阵快速幂
我tm傻逼了 和上文一样,一直都是以【F(n),F(n-1),F(n-2)】去递推
然后这个题发现推第三项很困难 - - 发呆一小时
既然F(n)可以由F(n-1) F(n-2) 推过来 那么直接在递推矩阵里面实现不就好了 - - 傻逼了傻逼了
假设C(n)=(a+sqrt(b) )n + (a-sqrt(b) )n
(a-1)2 <b<a2 那么对于【S1=a+sqrt(b)】 可以知道a>sqrt(b)>a-1
那么显然 S1=2*a 也就是说 【C(n)】=S(n)
接下来就是推C(n)了 - - – 很简单自己推一下吧

#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
inline ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}


int aa,bb,n,mod;
struct Matrix {
  int a[9][9];
  Matrix() { memset(a, 0, sizeof a); }
  Matrix operator*(const Matrix &b) const {
    Matrix res;
    for (int i = 1; i <= 2; ++i)
      for (int j = 1; j <= 2; ++j)
        for (int k = 1; k <= 2; ++k)
          res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]) % mod;
    return res;
  }
} ans, base;

void init() {
base.a[1][1]=0;
base.a[1][2]=((bb-aa*aa)%mod+mod)%mod;



  base.a[2][1]=1;
  base.a[2][2]=2*aa;

  ans.a[1][2] =(int)ceil((aa*aa%mod+bb)%mod+2*aa*sqrt(bb))%mod ;
  ans.a[1][1] =2*aa%mod;

}
/*
[p  1

 q  0]*/

void qpow(int b) {
  while (b) {
    if (b & 1) ans = ans * base;
    base = base * base;
    b >>= 1;
  }
}

signed main() {

  while(scanf("%lld%lld%lld%lld",&aa,&bb,&n,&mod)!=EOF){

  init();
  qpow(n-1);
printf("%lld\n",ans.a[1][1]%mod);

}
return 0;

}
    • 罢了矩阵快速幂就先练到这里

思维水题&数论不配
晚饭后A一题 大概意思就是一个很大的画板起初全是白色的 然后你有a次红色填涂的鸡会和b次蓝色颜色的填涂鸡会,最终形成的图形要满足
首先是个矩阵包含了a+b块颜色的格子 然后至少有一种颜色的格子能够形成矩形 问我们构造出来的这种矩形的最小周长是多少
刚开始我想当的是纯粹是个给你a+b 也就是总面积s=a+b 的 矩形 求它的最小面积 然后交了一发WA37 好叭我承认没读懂题QAQ
实际上要这样子枚举它 枚举边i =1开始 i*i<=s 然后因为我们要至少使得红色或者蓝色的块是矩形 要满足a%i=0 或者b%i =0 所以满足这个条件的i 边长 才能考虑拿去做整体矩形的边长 然后我们判断n%i=0 满足就进行整体周长的最小值维护 就OK了

#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#include<set>
#define ll long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
 ll gcd(ll a,ll b){if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){ll ans=1;if(b==0){return ans%mod;}while(b){if(b%2==1){b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){ll ans = 1;a%=p;while(b){if(b&1){ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元   (分子*qp(分母,mod-2,mod))%mod;

ll fact_pow(ll n,ll p){ll res=0;while(n){n/=p;res+=n;}return res;}
ll mult(ll a,ll b,ll p)
{
    a%=p;
    b%=p;
    ll r=0,v=a;
    while(b)
    {
        if(b&1)
        {
            r=(r+v)%p;

               r=(r+p)%p;
        }
        v<<=1;
        v=(v+p)%p;
        b>>=1;
    }
    return r%p;
}
ll pow_mod(ll x,ll n,ll mod)
{
    ll res=1;
    while(n)
    {
        if(n&1)
        res=mult(res,x,mod);
        x=mult(x,x,mod);
        n>>=1;
    }
    return res;
}
ll quick_pow(ll a,ll b,ll p){ll r=1,v=a%p;while(b){if(b&1)r=mult(r,v,p);v=mult(v,v,p);b>>=1;}return r;}
bool CH(ll a,ll n,ll x,ll t)
{ll r=quick_pow(a,x,n);ll z=r;for(ll i=1;i<=t;i++){r=mult(r,r,n);if(r==1&&z!=1&&z!=n-1)return true;z=r;}return r!=1;}
bool Miller_Rabin(ll n)
{if(n<2)return false;if(n==2)return true;if(!(n&1))return false;ll x=n-1,t=0;while(!(x&1)){x>>=1;t++;}
srand(time(NULL));ll o=8;for(ll i=0;i<o;i++){ll a=rand()%(n-1)+1;if(CH(a,n,x,t))return false;}return true;}
ll exgcd(ll a,ll b,ll &x,ll &y){
    if (!b){
        x=1,y=0;
        return a;
    }
    ll ans=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return ans;
}
ll INV(ll a,ll b){ll x,y;return exgcd(a,b,x,y),(x%b+b)%b;}
ll crt(ll x,ll p,ll mod){return INV(p/mod,mod)*(p/mod)*x;}
ll FAC(ll x,ll a,ll b)
{if(!x)return 1;ll ans=1;for(ll i=1;i<=b;i++)if(i%a)ans*=i,ans%=b;
ans=pow_mod(ans,x/b,b);for(ll i=1;i<=x%b;i++)if(i%a)ans*=i,ans%=b;return ans*FAC(x/a,a,b)%b;}
ll C(ll n,ll m,ll a,ll b)
{ll N=FAC(n,a,b),M=FAC(m,a,b),Z=FAC(n-m,a,b),sum=0,i;for(i=n;i;i=i/a)sum+=i/a;
for(i=m;i;i=i/a)sum-=i/a;for(i=n-m;i;i=i/a)sum-=i/a;return N*pow_mod(a,sum,b)%b*INV(M,b)%b*INV(Z,b)%b;}
ll exlucas(ll n,ll m,ll p)
{ll t=p,ans=0,i;for(i=2;i*i<=p;i++){ll k=1;while(t%i==0){k*=i,t/=i;}
ans+=crt(C(n,m,i,k),p,k),ans%=p;}if(t>1)ans+=crt(C(n,m,t,t),p,t),ans%=p;return ans % p;}
ll H(ll x,ll p)  //错排
{
       ll ans=0;
    if(x==0)return 1;
    x=x%(2*p);
    if(x==0)x=2*p;
    for(int i=2;i<=x;++i)
    ans=(ans*i+(i%2==0?1:-1))%p;
    return (ans+p)%p;
}

set<ll>seet;
int main(){
ll add=1e17;
ll a,b,s;
read(a);
read(b);
ll op=gcd(a,b);
ll rnm=min(a,b);
//read(s);
s=a+b;
for(ll i=1;i*i<=s;i++){
if(a%i==0){
seet.insert(a/i);
}
if(b%i==0){
    seet.insert(b/i);
}
if(s%i==0){
 if(*seet.begin()<=s/i){
 add=min(add,i*2+s/i*2);
 }
}
}
printf("%lld\n",add);
return 0;
}

正解没暴力好理解的exgcd题
给我们n p w d 和xw+yd=p这个式子 exgcd能提供一组解但是不一定符合题意 根据线代的知识 通解啥的带进去枚举搞就好了

 
int main(){
 
	ll n=read(),p=read(),w=read(),d=read();
 
	for(int y=0;y<w;y++){
		if((p-d*y)%w){
        continue;}
		ll x=(p-d*y)/w;
		if(y+x<=n&&x>=0){
			cout<<x<<" "<<y<<" "<<n-y-x;
			return 0;
		}
		else break;
	}
	cout<<"-1";
	return 0;
}

害,看了眼数据结构专题好像没一个会写的 (大佬们7 8题起步 ORZ
现场学一手单调队列维护 签到
太菜了 明天开始数据结构 操了

2233333矩阵

 #include<bits/stdc++.h>
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
inline ll read(){char c=getchar();ll f=1,x=0;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^'0');c=getchar();}return x*f;}
const int mod =1e7+7;

int aa,bb,n,m;
struct Matrix {
  int a[25][25];
  Matrix() { memset(a, 0, sizeof a); }
  Matrix operator*(const Matrix &b) const {
    Matrix res;
    for (int i = 1; i <=n+2; ++i)
      for (int j = 1; j <=n+2; ++j)
        for (int k = 1; k <=n+2; ++k)
          res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]) % mod;
    return res;
  }
} ans, base;

void init() {
memset(ans.a,0,sizeof(ans.a));
memset(base.a,0,sizeof(base.a));
    ans.a[1][1]=23;
    for(int i=2;i<=n+1;i++){
        ans.a[1][i]=read();
    }
    ans.a[1][n+2]=3;   //n+2 行初始矩阵

 for(int i=1;i<=n+1;i++){
    base.a[1][i]=10;
    base.a[n+2][i]=1;
 }
 base.a[1][n+2]=0;
 base.a[n+2][n+2]=1;
 for(int i=2;i<=n+1;i++){

    for(int j=1;j<=n+1;j++){
        if(j>=i){
        base.a[i][j]=1;}
        else{
            base.a[i][j]=0;
        }
    }
 }


}
/*
[p  1

 q  0]*/

void qpow(int b) {
  while (b) {
    if (b & 1) ans = ans * base;
    base = base * base;
    b >>= 1;
  }
}
signed main() {
  while(scanf("%lld%lld",&n,&m)!=EOF){
  init();
  qpow(m);
printf("%lld\n",ans.a[1][n+1]%mod);
}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值