64位整数乘法
求 a 乘 b 对 p 取模的值。
输入格式
第一行输入整数a,第二行输入整数b,第三行输入整数p。
输出格式
输出一个整数,表示ab mod p的值。
数据范围
1≤a,b,p≤1018
输入样例:
3
4
5
输出样例:
2
本题思路: O(logn)
由于直接计算会超过long long 的最大范围,所以采用类似快速幂的方法
举个栗子~
例:3 x 7
7的二进制:111
3 x(2^0)=3
3x(2^1)=6
3x(2^2)=12
sum=3+6+7=21=3 x 7
每次结果位前一次2
快速幂模板
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int qmi(int a, int k, int p) // 求a^k mod p
{
int res = 1 ;
while (k)
{
if (k & 1) res =(LL) res * a % p;//二进制中该位为1
a = (LL)a * a % p;累乘a
k >>= 1;//二进制右移一位
}
return res;
}
int main()
{
int n;
cin>>n;
int a,b,c;
while (n -- )
{
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",qmi(a,b,c));
}
return 0;
}
本题代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
LL a,b,p,res;
cin>>a>>b>>p;
res=0;
while(b)
{
if(b&1)
res=(res+a)%p;
a=a*2%p;
b>>=1;
}
cout<<res<<endl;
return 0;
}
95. 费解的开关
你玩过“拉灯”游戏吗?
25 盏灯排成一个 5×5 的方形。
每一个灯都有一个开关,游戏者可以改变它的状态。
每一步,游戏者可以改变某一个灯的状态。
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯。
下面这种状态
10111
01101
10111
10000
11011
在改变了最左上角的灯的状态后将变成:
01111
11101
10111
10000
11011
再改变它正中间的灯后状态将变成:
01111
11001
11001
10100
11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在 6 步以内使所有的灯都变亮。
输入格式
第一行输入正整数 n,代表数据中共有 n 个待解决的游戏初始状态。
以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。
每组数据描述了一个游戏的初始状态。
各组数据间用一个空行分隔。
输出格式
一共输出 n 行数据,每行有一个小于等于 6 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若 6 步以内无法使所有灯变亮,则输出 −1。
数据范围
0<n≤500
输入样例:
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
输出样例:
3
2
-1
解题思路
本题看见0,1首先想到二进制位运算,
首先枚举第一行,第一行有五位,则第一行2^5=32种按法,每次从下一行查看竖直上方对应的灯是否要按,最终每次min(res),如果res<6并且每盏灯都打开则符合输出res
否则输出-1
#include <bits/stdc++.h>
using namespace std;
const int N=6;
int dx[N]={-1,0,1,0,0};
int dy[N]={0,1,0,-1,0};
char g[N][N],backup[N][N];
void turn(int x,int y)
{
for(int i=0;i<5;i++)
//枚举该点和上,下,左,右
{
int a=dx[i]+x;
int b=y+dy[i];
if(a<0||a>=5||b<0||b>=5)continue;
g[a][b]^=1;//异或,如果是一个偶数 ^ 1,那么结果是偶数 +1;如果是一个奇数 ^ 1,那么结果是奇数 -1
//例如:0^1=1 1^1=0
}
}
int main()
{
int n;
cin>>n;
while(n--)
{
for(int i=0;i<5;i++)cin>>g[i];//输入初始化
int res=10;
for(int op=0;op<32;op++)//2^5=32,第一行的按法有32种情况,枚举0~31的二进制
{
memcpy(backup,g,sizeof g);//copy,用于还原,使其32次种不同情况
int step=0;//操作数
for(int i=0;i<5;i++)//按第一行
if(op>>i&1)例如2,二进制为00010,则操作数为1
{
step++;
turn(0,i);
}
for(int i=0;i<4;i++)
for(int j=0;j<5;j++)
if(g[i][j]=='0')
{
step++;
turn(i+1,j);
}
bool dark=false;
for(int j=0;j<5;j++)
if(g[4][j]=='0')
{
dark=true;
break;
}
if(!dark)res=min(res,step);
memcpy(g,backup,sizeof g);//此处为还原
}
if(res>6)res=-1;
cout<<res<<endl;
}
return 0;
}
1015. 摘花生
Hello Kitty想摘点花生送给她喜欢的米老鼠。
她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。
地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。
Hello Kitty只能向东或向南走,不能向西或向北走。
问Hello Kitty最多能够摘到多少颗花生。
1.gif
输入格式
第一行是一个整数T,代表一共有多少组数据。
接下来是T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。
输出格式
对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。
数据范围
1≤T≤100,
1≤R,C≤100,
0≤M≤1000
此题思路较为简单,数字三角形模型即可
直接上代码
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int w[N][N],f[N][N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>w[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
f[i][j]=max(f[i-1][j],f[i][j-1])+w[i][j];
cout<<f[n][m]<<endl;
}
return 0;
}
1018. 最低通行费
一个商人穿过一个 N×N 的正方形的网格,去参加一个非常重要的商务活动。
他要从网格的左上角进,右下角出。
每穿越中间 1 个小方格,都要花费 1 个单位时间。
商人必须在 (2N−1) 个单位时间穿越出去。
而在经过中间的每个小方格时,都需要缴纳一定的费用。
这个商人期望在规定时间内用最少费用穿越出去。
请问至少需要多少费用?
注意:不能对角穿越各个小方格(即,只能向上下左右四个方向移动且不能离开网格)。
输入格式
第一行是一个整数,表示正方形的宽度 N。
后面 N 行,每行 N 个不大于 100 的正整数,为网格上每个小方格的费用。
输出格式
输出一个整数,表示至少需要的费用。
数据范围
1≤N≤100
输入样例:
5
1 4 6 8 10
2 5 7 15 17
6 8 9 18 20
10 11 12 19 21
20 23 25 29 33
输出样例:
109
样例解释
样例中,最小值为 109=1+2+5+7+9+12+19+21+33。
此题思路与上题相似:
虽说题目中说明步数小于等于2N-1,其暗示只能往右或下走,与上题类似,所以不同点在于一个求max。一个求min
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=110;
int w[N][N];
int f[N][N];
int main()
{
int n;
cin>>n;
memset(f,0x3f,sizeof f);//初始化为正无穷,就不会从地图外走进
f[0][1]=f[1][0]=f[0][0]=0;
f[1][1]=w[1][1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>w[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i-1][j],f[i][j-1])+w[i][j];
cout<<f[n][n]<<endl;
return 0;
}