寒假每日一题之疯狂补题!
小明正在玩一个“翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:**oo***oooo
如果同时翻转左边的两个硬币,则变为:oooo***oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
输入格式
两行等长的字符串,分别表示初始状态和要达到的目标状态。
输出格式
一个整数,表示最小操作步数
数据范围
输入字符串的长度均不超过100。
数据保证答案一定有解。
输入样例1:
**********
o****o****
输出样例1:
5
输入样例2:
*o**o***o***
*o***o**o***
输出样例2:
1
出自于第四届蓝桥杯B组的题目。会想到八数码这个题,进行多少操作会变成目标状态。用bfs会超时。
先观察一下性质。①操作顺序对答案无影响。②每一个操作最多进行一次。
第一个硬币和最后一个硬币是否需要操作只需要看他本身,所有都是唯一确定的,不需要枚举。看似是个宽搜,实际上是个递推,最终方案也就只有一种。
#include
#include
#include
#include
#include
#include
#include
#include
#include
伊娃喜欢从整个宇宙中收集硬币。
有一天,她去了一家宇宙购物中心购物,结账时可以使用各种硬币付款。
但是,有一个特殊的付款要求:每张帐单,她只能使用恰好两个硬币来准确的支付消费金额。
给定她拥有的所有硬币的面额,请你帮她确定对于给定的金额,她是否可以找到两个硬币来支付。
输入格式
第一行包含两个整数 N 和 M,分别表示硬币数量以及需要支付的金额。
第二行包含 N 个整数,表示每个硬币的面额。
输出格式
输出一行,包含两个整数 V1,V2,表示所选的两个硬币的面额,使得 V1≤V2并且 V1+V2=M。
如果答案不唯一,则输出 V1 最小的解。
如果无解,则输出 No Solution
。
数据范围
1≤N≤10^5
1≤M≤1000
输入样例1:
8 15
1 2 8 7 2 4 11 15
输出样例1:
4 11
输入样例2:
7 14
1 8 7 2 4 11 15
输出样例2:
No Solution
很好的考察哈希表。此时数据范围是10^5,所以时间复杂度就是O(nlogn)[数据范围也很重要]
因为V1+V2=M,就是查找这个数的前面有没有一个数等于M-这个数,就是查找一个数是否存在,所以可以用哈希表来写,从小到大扫描的时候,每扫描一个数,就把它插在哈希表里面,对于当前数要看他前面有没有这个数,就在哈希表里面查一下。每个数遍历一次,O(n)。
#include
#include
#include
#include
#include
#include
#include
#include
#include
先将整个数组从小到大排序,对于ai+aj<=M且j最大。如果前面的指针单调从前往后走,且后面的指针单调的从后往前走,那么这个时候就可以使用双指针的算法。双指针O(n),排序O(logn)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=100010;
int n,m;
int w[i];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;im)j--;
if(i
但后面会发现,哈希表的运行速度是慢于双指针的,这是由于哈希表的STL比较慢,而且时间嘛,不能只看复杂度,还要看常数,双指针虽然时间复杂度高啊,但是他的常数比较小。
十三号星期五真的很不常见吗?
每个月的十三号是星期五的频率是否比一周中的其他几天低?
请编写一个程序,计算 N年内每个月的 13 号是星期日,星期一,星期二,星期三,星期四,星期五和星期六的频率。
测试的时间段将会开始于 1900年 1月 1日,结束于 1900+N−1 年 12 月 31日。
一些有助于你解题的额外信息:
输入格式
共一行,包含一个整数 NN。
输出格式
共一行,包含七个整数,整数之间用一个空格隔开,依次表示星期六,星期日,星期一,星期二,星期三,星期四,星期五在十三号出现的次数。
数据范围
1≤N≤400
输入样例:
20
输出样例:
36 33 34 33 35 35 34
这一道星期几的题目有很多种做法,还有公式,基姆拉尔森公式,但公式做法不提倡,无法提高代码能力。就用个通用做法,就枚举天12w的计算量也还可以接受,枚举月会更快一些。枚举每月第一天距离1900年1月1号(起点)过了多少天(偏移量)。(偏移量+12)%7余几就可以了。有特殊的地方就是判断平年和闰年。
闰年 情况1:不能整除100但可以整除4;情况2:可以整除400;
在枚举月的时候可以开数组,很快的。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int moth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};//打表
int weekday[7];
int main()
{
int n;
cin>>n;
for(int year=1900;year<1900+n;year++)//年
{
for(int i=1;i<=12;i++)//月
{
weekday[(days+12)%7]++;
days+=month[i];
if(i==2)
{
if(year%100&&year%4==0||year%400==0)
days++;
}
}
}
for(int i=5,j=0;j<7;i=(i+1)%7,j++)
cout<
输入整数N,输出一个N阶的二维数组。
数组的形式参照样例。
输入格式
输入包含多行,每行包含一个整数N。
当输入行为N=0时,表示输入结束,且该行无需作任何处理。
输出格式
对于每个输入整数N,输出一个满足要求的N阶二维数组。
每个数组占N行,每行包含N个用空格隔开的整数。
每个数组输出完毕后,输出一个空行。
数据范围
0≤N≤100
输入样例:
1
2
3
4
5
0
输出样例:
1
1 2
2 1
1 2 3
2 1 2
3 2 1
1 2 3 4
2 1 2 3
3 2 1 2
4 3 2 1
1 2 3 4 5
2 1 2 3 4
3 2 1 2 3
4 3 2 1 2
5 4 3 2 1
不同的看法,不同的解法。有的时候写不出来,可以换一个看法。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=110;
int main()
{
int n;
while(cin>>n,n)
{
for(int i=1;i<=n;i++)
{
for(int j=i,k=1;j<=n;j++,k++)//great!这样子来表示好巧
{
a[i][j]=k;
a[j][i]=k;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
int n;
while(cin>>n,n)
{
for(int i=1;i<=n;i++)
{
for(int j=i;j>=1;j--)
cout<
这个方法都不用数组了!
找每一个数跟他的行的关系:|i-j|+1
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
int n;
while(cin>>n,n)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<
给定一个N×N 的棋盘,请你在上面放置 N 个棋子,要求满足:
1 2 3 4 5 6
-------------------------
1 | | O | | | | |
-------------------------
2 | | | | O | | |
-------------------------
3 | | | | | | O |
-------------------------
4 | O | | | | | |
-------------------------
5 | | | O | | | |
-------------------------
6 | | | | | O | |
-------------------------
上图给出了当 N=6 时的一种解决方案,该方案可用序列 2 4 6 1 3 5
来描述,该序列按顺序给出了从第一行到第六行,每一行摆放的棋子所在的列的位置。
请你编写一个程序,给定一个 N×N 的棋盘以及 N 个棋子,请你找出所有满足上述条件的棋子放置方案。
输入格式
共一行,一个整数 N。
输出格式
共四行,前三行每行输出一个整数序列,用来描述一种可行放置方案,序列中的第 ii 个数表示第 ii 行的棋子应该摆放的列的位置。
这三行描述的方案应该是整数序列字典序排在第一、第二、第三的方案。//你要按照正常人的做法做就可以了哈哈哈哈
第四行输出一个整数,表示可行放置方案的总数。
数据范围
6≤N≤13//一般都是13
输入样例:
6
输出样例:
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
十分经典的暴搜问题,叫八皇后(n皇后)问题。超超超超经典哦!为了理解,自己可以画一下递归搜索树。 按行来枚举 ,一般有对称方法。
dfs天然保证字典序。还要注意一点,恢复现场
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=15;
int n;
bool col[N],dg[N*2],udg[N*2];//后面两个是对角线和反对角线
int path[N],ans;
void dfs(int x)
{
if(x>n)
{
ans++;
if(ans<=3)//输出前三个方案
{
for(int i=1;i<=n;i++)
cout<>n;
dfs(1);
cout<
给定 V 种货币(单位:元),每种货币使用的次数不限。
不同种类的货币,面值可能是相同的。
现在,要你用这 V种货币凑出 N元钱,请问共有多少种不同的凑法。
输入格式
第一行包含两个整数 V 和 N。
接下来的若干行,将一共输出 VV 个整数,每个整数表示一种货币的面值。
输出格式
输出一个整数,表示所求总方案数。
数据范围
1≤V≤25
1≤N≤10000
答案保证在long long
范围内。
输入样例:
3 10
1 2 5
输出样例:
10
完全背包问题
dp分析法,从两个地方考虑,①状态表示②状态计算,dp的方法比暴搜好呢是因为dp呢他是可以解决一类问题,而暴搜呢就是只能解决一个问题,暴搜dfs的时间复杂度就是指数级别的。背包定义是两维,表示的是哪一个集合。dp有点跟数学归纳法类似。
①分为集合(所有满足条件的集合,从1~i中选,且总钱数为j的方案的集合)还有属性(就是这个题问的是什么,本题就是数量)
②对应的是集合划分,分解为若干个子集,然后各个击破,最后一个不同点。
f(i,j)的意思是所有从1~i中选,且花钱是j的方案的集合。f(i,j)=f(i-1,j)+f(i,j-vi),然后再考虑优化,先优化时间,在优化空间
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=30,M=10010;
int n,m;
LL f[N][M];
int main()
{
cin>>n>>m;
f[0][0]=1;
for(int i=1;i<=n;i++)
{
int v;
cin>>v;
for(int j=0;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(j>=v)
f[i][j]+=f[i][j-v];
}
}
cout<
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=30,M=10010;
int n,m;
LL f[M];
int main()
{
cin>>n>>m;
f[0]=1;
for(int i=1;i<=n;i++)
{
int v;
cin>>v;
for(int j=v;j<=m;j++)
{
if(j>=v)
f[j]+=f[j-v];
/*f[i][j]=f[i-1][j]+f[i][j-v]*/
}
}
cout<
NN 的阶乘(记作 N!)是指从 1 到 N(包括 1 和 N)的所有整数的乘积。
阶乘运算的结果往往都非常的大。
现在,给定数字 N,请你求出 N!的最右边的非零数字是多少。
例如 5!=1×2×3×4×5=120,所以 5! 的最右边的非零数字是 2。
输入格式
共一行,包含一个整数 N。
输出格式
输出一个整数,表示 N! 的最右边的非零数字。
数据范围
1≤N≤1000
输入样例:
7
输出样例:
4
一看到这一道题我就想到了N^N的最高位,但这一题可以发现规律,末位数就是1和偶数(除了0),去0就是除以10^k,mod 0就是所求的数字,(分解质因数的思想)分解一下2,5的那个系数的最小值就是k
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
int n;
cin>>n;
int res=1,d2=0,d5=0;//d2和d5是2和5的数量
for(int i=1;i<=n;i++)
{
int x=i;
while(x%2==0)x/=2,d2++;
while(x%5==0)x/=5,d5++;
res=res*x/10;
}
int k=min(d2,d5);
for(int i=0;i
还有25道题,干!