位运算、递推与递归

目录

位运算

1.64位整数乘法

递推与递归

1.费解的开关

2.约数之和

3.分形之城


位运算

1.64位整数乘法

64位整数乘法 (nowcoder.com)

这题就是很简单的龟速乘,因为1e=18*1e18会爆longlong,假如编译器支持可以用__int128_t,或者高精度也行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll qadd(ll a,ll k,ll p)//龟速乘
{
    ll res=0;//加法的零元是0
    while(k)
    {
        if(k&1) res=(res+a)%p;
        a=(a+a)%p;
        k>>=1;
    }
    return res;
}
int main()
{
    ll a,b,p;
    scanf("%lld%lld%lld",&a,&b,&p);
    printf("%lld\n",qadd(a,b,p));
    return 0;
}

递推与递归

1.费解的开关

费解的开关 (nowcoder.com)

这题有多种做法,其中有bfs,或者终止状态递推6步,还有高斯消元的做法,现在让我们看看递推的做法

二进制枚举第一行所有会变到的状态,1表示改变这个位置,0表示不变,然后将第一锁死看第二行,枚举第二行的上一行假如上一行有0,则将这一行的这一位改变一下,这样就使得上一行的0全都变成1了,直到操作到最后一行,看看最后一行是不是全为0即可

#include<bits/stdc++.h>
using namespace std;
const int N=6;
char str[N][N],temp[N][N];
int dx[6]={-1,0,1,0,0},dy[6]={0,1,0,-1,0};//上 右 下 左 中
void trans(int x,int y)//用来改变一个位置
{
    for(int i=0;i<5;i++)//枚举五个方向
    {
        int tx=x+dx[i],ty=y+dy[i];
        if(tx<0||tx>4||ty<0||ty>4) continue;
        temp[tx][ty]^=1;
    }
}
void solve()
{
    for(int i=0;i<5;i++) scanf("%s",str[i]);
    int ans=7;
    for(int i=0;i<32;i++)
    {
        int cnt=0;
        memcpy(temp,str,sizeof str);
        for(int j=0;j<5;j++)//枚举改第一行的状态
            if(i>>j&1) cnt++,trans(0,j);
        for(int j=0;j<4;j++)//枚举改剩下的几行
          for(int k=0;k<5;k++)
              if(temp[j][k]=='0') cnt++,trans(j+1,k);
        for(int j=0;j<5;j++)//看看最后几行是不是全为1
           if(temp[4][j]=='0') cnt=0x3f3f3f3f;
        ans=min(cnt,ans);
    }
    if(ans<=6) printf("%d\n",ans);//假如小于6了
    else puts("-1");
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--) solve();
    return 0;
}

2.约数之和

97. 约数之和 - AcWing题库

约数之和的公式:

 求等比数列也有公式就是p^k-1/p-1

然后这题用递归来做定义sum(p,k)是约数为p,次方是k的前k相等比数列的和

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=9901;
int a,b;
int qmi(int a,int k)
{
    int res=1;
    while(k)
    {
        if(k&1) res=(ll)res*a%mod;
        a=(ll)a*a%mod;
        k>>=1;
    }
    return res;
}
int sum(int p,int k)//用来求sum
{
    if(k==1) return 1;//假如是1了,就返回1
    if(k&1) return (sum(p,k-1)+qmi(p,k-1))%mod;//奇数
    else return ((1+qmi(p,k/2))*sum(p,k/2))%mod;//偶数
}
int main()
{
    int ans=1;
    cin>>a>>b;
    for(int i=2;i<=a/i;i++)//分解质因数
        if(a%i==0)
        {
            int s=0;
            while(a%i==0) s++,a/=i;//获取质因数的个数
            ans=(ll)ans*sum(i,b*s+1)%mod;//按照公式求一遍
        }
    if(a>1) ans=(ll)ans*sum(a,b+1)%mod;//假如最后也是个质因数
    if(a==0) ans=0;
    cout<<ans<<endl;
    return 0;
}

3.分形之城

98. 分形之城 - AcWing题库

这题就是找规律递归到子问题

n层是可以由n-1层得到的,只不过的经过坐标变化,然后在分别求一下坐标变化需要改变的值即可

get(N,A)表示在第N层获取A这个点的坐标,然后距离直接就两点间距离公式即可 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Piont//用来存坐标
{
    ll x,y;
};
Piont get(ll n,ll a)
{
    if(n==0) return {0,0};//假如0层了,说明只有0,0这一个点
    ll block=1ll<<2*n-2,len=1ll<<n-1;
    auto d=get(n-1,a%block);//处理子问题
    ll x=d.x,y=d.y;
    int z=a/block;
    //图中每种情况
    if(z==0) return {y,x};
    else if(z==1) return {x,y+len};
    else if(z==2) return {x+len,y+len};
    else return {len+len-1-y,len-1-x};
}
void solve()
{
    ll n,a,b;
    scanf("%lld%lld%lld",&n,&a,&b);
    auto da=get(n,a-1),db=get(n,b-1);//获取a,b的坐标,因为数是0开始记的,所以要减1
    double dx=da.x-db.x,dy=da.y-db.y;
    printf("%.0lf\n",sqrt(dx*dx+dy*dy)*10);//输出两点间距离
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--) solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值