题解
A - 最低位
题目:读入一个整数,对它的二进制形式进行操作:取从他的右边向左边第一个不为0的一段二进制数,转换成十进制形式。如,26的二进制形式是11010,取出10这一段,输出8。
int c(0);
while(~ n & 1)//与运算
{
c++;
n >>= 1;//右移运算
}
cout << pow(2, c)<<endl;//重新转换成十进制
B - 杰米和二进制序列(补题)
题目:找到k个整数,使得每个数的幂的2的总和等于数n,并且答案中的最大整数尽可能小。 由于可能有多个答案,因此要求输出按字典顺序排列的最大答案。
- 位运算
#include<cstdio>
int ans[100005],v[100005];
int main()
{
long long n,k;
scanf("%lld%lld",&n,&k);
int i,index=0,cnt=0;//cnt记录已经拆了多少个
//先拆成2进制
while(n)
{
if(n%2==1)
{
v[index]=1;
cnt++;
}
index++;
n/=2;
}
//如果cnt已经大于k,cnt当前记录的是最少要拆几个
if(cnt>k)
{
printf("No\n");
return 0;
}
printf("Yes\n");
int minn;
//二进制顺序反转
for(i=0; i<index; i++)
{
ans[i]=v[index-i-1];
}
//找到最小的二进制为1的数minn,最大的不够拆了从minn开始拆
for(i=0; i<index; i++)
{
if(ans[i])
minn=i;
}
//从头开始拆(保证了y尽可能小)
for(i=0;; i++)
{
if(cnt==k)
break;
if(ans[i]+cnt<=k)//这个判断是精髓部分
{
cnt+=ans[i];
ans[i+1]+=ans[i]*2;
ans[i]=0;
}
else
break;
if(i+1>minn)
minn=i+1; //更新最小值下标
}
//从最小值开始拆(保证了按照字典树最小)
for(;; i++)
{
if(cnt==k)
break;
cnt++;
ans[minn]--;
ans[minn+1]+=2;
minn++;
}
//找到输出下标上限
int a=index>i?index-1:i;
a=minn>a?minn:a;
//输出
for(i=0; i<=a; i++)
{
while(ans[i])
{
ans[i]--;
minn=index-i-1;
printf("%d ",minn);
}
}
printf("\n");
return 0;
}
C - 麦哲伦的异或
题目:对一个长度为n的数组,求所有的 x o r ( A i + A j ) ( 1 ≤ i , j ≤ n ) xor(Ai + Aj)(1≤i,j≤n) xor(Ai+Aj)(1≤i,j≤n)。阵列B的xor定义为 B 1 x o r B 2... x o r B n B1 xor B2 ... xor Bn B1xorB2...xorBn
- 位运算
- 异或运算3的性质运用( a x o r a = 0 , 0 x o r a = a a xor a = 0, 0 xor a = a axora=0,0xora=a)
- 注意点:
He wants to know the xor of all (Ai+Aj)(1≤i,j≤n)
其实是指所有的 ( A i + A j ) (Ai+Aj) (Ai+Aj)的组合的异或。如,当n = 3, 输出的就是 ( A 1 + A 1 ) x o r ( A 1 + A 2 ) x o r ( A 1 + A 3 ) x o r ( A 2 + A 1 ) x o r ( A 2 + A 2 ) x o r ( A 2 + A 3 ) x o r ( A 3 + A 1 ) x o r ( A 3 + A 1 ) x o r ( A 3 + A 2 ) x o r ( A 3 + A 3 ) (A1 + A1) xor (A1 + A2) xor (A1 + A3) xor (A2 + A1) xor (A2 + A2 ) xor (A2 + A3) xor (A3 + A1) xor (A3 + A1) xor (A3 + A2) xor (A3 + A3) (A1+A1)xor(A1+A2)xor(A1+A3)xor(A2+A1)xor(A2+A2)xor(A2+A3)xor(A3+A1)xor(A3+A1)xor(A3+A2)xor(A3+A3) - 多组输入
int T;
cin >> T;
while(T--){}
- 逻辑部分(最容易想到的就是暴力求所有的异或,但是会超时的。再想想,其实根据 a x o r a = 0 , 0 x o r a = a a xor a = 0, 0 xor a = a axora=0,0xora=a可以想到,最后求得是所有 ( A i + A j ) , i = j (Ai+Aj),i=j (Ai+Aj),i=j时的组合的异或):
cin >> n >> m >> z >> l;
ll A = 0;
for(ll i=2; i<=n; i++)
{
A = (A * m + z) % l;
s ^= (A+A);
}//这里要注意怎么排除情况,减小运算量
cout << s << endl;
D - a的b次(样题)
题目:给你两个数A和B,计算A的B次方,输出A的B次方的最后三位数所表示的整数。
- 快速幂(整数)
- 主要需要理解怎么利用位运算进行快速幂计算
- a=0,b=0时停止的多组输入
while(cin>>a>>b && a && b)
{
cout << quickPow(a, b) <<endl;
}
- 快速幂函数部分
- 示范:对于 x 11 x^{11} x11,11→ ( 1011 ) 2 (1011)_2 (1011)2,过一遍快速幂函数
n&1 | res | x |
---|---|---|
1 | x x x | x 2 ( x 2 1 ) x^2(x^{2^1}) x2(x21) |
1 | x ∗ x 2 x*x^2 x∗x2 | x 4 ( x 2 2 ) x^4(x^{2^2}) x4(x22) |
0 | x ∗ x 2 x*x^2 x∗x2 | x 8 ( x 2 3 ) x^8(x^{2^3}) x8(x23) |
1 | x ∗ x 2 ∗ x 8 x*x^2*x^8 x∗x2∗x8 | x 16 ( x 2 4 ) x^{16}(x^{2^4}) x16(x24) |
#define ll long long
ll quickPow(ll x, ll n)//n是指数
{
ll res = 1;
while(n > 0)
{
if(n & 1) res = res * x % 1000;//这里根据题意题目每次取后三位,应用到其他题目时可以灵活变通
x = x * x % 1000;
n >>= 1;
}
return res;
}
E - 取模运算
题目:给出一个整数M以及H组A和B,求 ( A 1 B 1 + A 2 B 2 + . . . + A H B H ) m o d M . (A_1^{B_1}+A_2^{B_2}+ ... +A_H^{B_H})mod M. (A1B1+A2B2+...+AHBH)modM.
- 快速幂(整数)
- 快速幂的应用,主要在于对m的取模
- 输入部分(Z是多个实例输入):
int z;
cin >> z;
while(z--)
{
int m, tt, s(0);
cin >> m >> tt;
while(tt--)
{
int a, b;
cin >> a >> b;
s += quickpow(a, b, m);
}
cout << s % m << endl;
}
- 快速幂函数部分:
ll quickpow(ll x, ll n, ll m)
{
ll res = 1;
while(n > 0)
{
if(n & 1) res = res * x % m;
x = x * x % m;
n >>= 1;
}
return res;
}
F - 一系列数字
题目:n个序列(等差/等比数列),给出每个序列的前三个,求数列中指定位置的数
- 快速幂(整数)
- 快速幂的应用
- 注意点:对200907取模。
- 多组输入
ll N;//ll is long long
cin >> N;
while(N--)
- 判断是等差还是等比数列
ll a, b, c, k;
cin >> a >> b >> c >> k;
if((b-a) == (c-b))
cout << (a + (k - 1) * (b - a)) % 200907<<endl;
else
cout << a * quickpow(b/a, k-1) % 200907 << endl;
- 快速幂函数部分
ll quickpow(ll x, ll n)
{
ll res = 1;
while(n > 0)
{
if(n & 1) res = res * x % 200907;
x = x * x % 200907;
n >>= 1;
}
return res;
}
G - Fibonacci
题目:求 F n F_n Fn
- 快速幂(矩阵)
- 矩阵快速幂的应用,可以由数的快速幂扩展过来
- 结构体的使用:
struct matrix
{
int m[3][3];
};
- 矩阵相乘函数部分:
matrix mul(matrix a,matrix b)
{
matrix c;
memset(c.m,0,sizeof(c.m));
int i,j,k;
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
for(k=1; k<=n; k++)
{
c.m[i][j]+=a.m[i][k]*b.m[k][j];
c.m[i][j]%=10000;
}
return c;
}
- 快速幂函数部分:
matrix quickpower(matrix ans,int k)
{
matrix res;
memset(res.m,0,sizeof(res.m));//矩阵的初始化
for(int i=1; i<=n; i++) res.m[i][i]=1;//数的快速幂是取1,矩阵的是取单位矩阵
while(k)
{
if(k&1)
res=mul(ans,res);
ans=mul(ans,ans);
k>>=1;
}
return res;
}
H - 神奇的函数
题目:接受一个矩阵 A 和一个正数 k,计算 A k A^k Ak,然后输出这个矩阵对角线元素之和。
- 快速幂(矩阵)
- 矩阵快速幂的应用,与G题的区别主要在于作为底数的矩阵变成了未知的,需要输入
- main函数内容的变化:
int main()
{
int sum, k, t;
cin>>t;
while(t--)
{
cin>>n>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>A.m[i][j];
A.m[i][j]%=9973;
}
B=quickpower(A,k);
sum=0;
for(int i=1;i<=n;i++)
{
sum+=B.m[i][i];
sum%=9973;
}
cout<<sum<<endl;
}
return 0;
}