目录
位运算
1.64位整数乘法
这题就是很简单的龟速乘,因为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.费解的开关
这题有多种做法,其中有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.约数之和
约数之和的公式:
求等比数列也有公式就是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.分形之城
这题就是找规律递归到子问题
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;
}