时间略紧,还以为是周二,,还想着将题目整理完好好写写,现在现把自己找到的资料哦总结一下吧,,我们A了三个题,有7个题没做出来,其中有三道题目是有感觉可以加把劲有希望的,,
其中一道模拟题,我有了大体的思路,但当时大家既听不进去,又寄希望于其他的题目,细节方面都没有实现,找到一篇博文,写的还挺详细的【原题啊,,】
https://blog.csdn.net/Wang_1997/article/details/65451808
大体说一下:
问题描述
你的一个朋友买了一台电脑。他以前只用过计算器,因为电脑的显示器上显示的数字的样子和计算器是不一样,所以当他使用电脑的时候会比较郁闷。为了帮助他,你决定写一个程序把在电脑上的数字显示得像计算器上一样。
输入数据
输入包括若干行,每行表示一个要显示的数。每行有两个整数 s 和 n (1 <= s <= 10, 0 <= n <= 99999999),这里 n 是要显示的数, s 是要显示的数的尺寸。
如果某行输入包括两个 0,表示输入结束。这行不需要处理。
输出要求
显示的方式是:用 s 个'-'表示一个水平线段,用 s 个'|'表示一个垂直线段。这种情况下,每一个数字需要占用 s+2 列和 2s+3 行。另外,在两个数字之间要输出一个空白的列。在输出完每一个数之后,输出一个空白的行。注意:输出中空白的地方都要用空格来填充。
输入样例
2 12345
3 67890
0 0
输出样例
-- -- --
| | || ||
| | || ||
-- -- -- --
|| | | |
|| | | |
-- -- --
--- --- --- --- ---
| || || || |
| || || || |
| || || || |
--- --- ---
| | || | || |
| | || | || |
| | || | || |
--- --- --- ---
解题思路
一个计算器上的数字显示单元,可以看作由以下编号从 1 到 7 的 7 个笔画组成:
我们可以说,数字 8 覆盖了所有的笔画,数字 7 覆盖笔画 1、 3 和 6,而数字 1覆盖笔画 3、 6。注意,每个笔画都是由 s 个’-‘或 s 个’|’组成。
输出时,先输出第 1 行,即整数 n 中所有数字里的笔画 1,然后输出第 2 行到第 s+1 行,即所有数字的笔画 2 和笔画 3,接下来是第 s+2 行,即所有数字的笔画 4,再接下来是第 s+3行到 2×s+2 行,,就是所有数字的笔画 5 和笔画 6,最后的第 2×s+3 行,是所有数字的笔
画 7。如果某个数字 d 没有覆盖某个笔画 m (m = 1…7),那么,输出数字 d 的笔画 m 的时候,就应该都输出空格;如果覆盖了笔画 m,则输出 s 个’-‘或 s 个’|’,这取决于笔画 m 是横的还是竖的。
由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画 1 覆盖情况的数组如下:
char n1[11] = {"- -- -----"};
其中, n1[i](i = 0……9) 代表笔画 1 是否被数字 i 覆盖。如果是,则 n1[i] 为'-',如果否,则 n1[i]为空格。上面的数组的值体现了笔画 1 被数字 0, 2, 3, 5, 6, 7, 8, 9 覆盖。对于竖向的笔画 2,由字符 '|' 组成,则记录其覆盖情况的数组如下:
char n2[11] = {"| ||| ||"};
该数组的值体现了笔画 2 被数字 0, 4, 5, 6, 8, 9 覆盖。
关键代码:
char n1[11] = {"- -- -----"}; //笔画 1 被数字 0, 2, 3, 5, 6, 7, 8, 9 覆盖
char n2[11] = {"| ||| ||"}; //笔画 2 被数字 0, 4, 5, 6, 8, 9 覆盖
char n3[11] = {"||||| |||"}; //笔画 3 被数字 0, 1, 2, 3, 4, 7, 8, 9 覆盖
char n4[11] = {" ----- --"}; //笔画 4 被数字 2, 3, 4, 5, 6, 8, 9 覆盖
char n5[11] = {"| | | | "}; //笔画 5 被数字 0, 2, 6, 8 覆盖
char n6[11] = {"|| |||||||"}; //笔画 6 被数字 0, 1, 3, 4, 5, 6, 7, 8, 9 覆盖
char n7[11] = {"- -- -- --"}; //笔画 7 被数字 0, 2, 3, 5, 6, 8, 9 覆盖
int main()
{
int s;
char szNumber[20];
int nDigit,nLength,i,j,k;
while(true){
cin >> s >> szNumber;
nLength = strlen(szNumber);
if(s == 0){
break;
}
for(i=0;i<nLength;i++){//输出所有数字的笔画 1
nDigit = szNumber[i] - '0';
cout<<" ";
for(j=0;j<s;j++){ //一个笔画由 s 个字符组成
cout<<n1[nDigit];
}
cout<<" ";
}
cout<<endl;
for(i=0;i<s;i++){//输出所有数字的笔画 2 和笔画 3
for(j=0;j<nLength;j++){
nDigit = szNumber[j]-'0';
cout<<n2[nDigit];
for(k=0;k<s;k++){
cout<<" ";//笔画 2 和笔画 3 之间的空格
}
cout<<n3[nDigit];
}
cout<<endl;
}
for(i=0;i<nLength;i++){//输出所有数字的笔画 4
nDigit = szNumber[i] - '0';
cout<<" ";
for(j=0;j<s;j++){
cout<<n4[nDigit];
}
cout<<" ";
}
cout<<endl;
for(i=0;i<s;i++){//输出所有数字的笔画 5 和笔画 6
for(j=0;j<nLength;j++){
nDigit = szNumber[j]-'0';
cout<<n5[nDigit];
for(k=0;k<s;k++){
cout<<" ";//笔画 5 和笔画 6 之间的空格
}
cout<<n6[nDigit];
}
cout<<endl;
}
for(i=0;i<nLength;i++){ //输出所有数字的笔画 7
nDigit = szNumber[i] - '0';
cout<<" ";
for(j=0;j<s;j++){
cout<<n7[nDigit];
}
cout<<" ";
}
cout<<endl;
}
return 0;
}
这个思路可以膜拜一下了,写出来代码简洁,我试图将每一个数字用二维数组表示出来,只是表示下来,就用了大半时间,又不懂到底怎么进行内部循环,最终也没有解出来,感觉还是有技巧的,再给我点时间,也不一定能够有这么简洁的思路。
以及一个杭电原题:
Problem B. Harvest of Apples
及其题解:https://blog.csdn.net/codeswarrior/article/details/81359075
其中涉及的莫队算法讲解:https://www.cnblogs.com/CsOH/p/5904430.html
我们将其理解为了卢卡斯定理的打表运用,当然是超时,,
D: 刘小强的苹果树
题目描述
刘小强的河里有n块石头,从1到n,请你帮他计算最多选取m块石头的方法数。
输入
第一行测试样例数T.
每个样例一行,两个数 n,m,(T<=1e5,n<=1e5,m<=1e5)
输出
输出方法数模1e9+7.
样例输入
2 5 2 1000 500样例输出
16 924129523
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int mod = 1e9+7;
ll fac[maxn],inv[maxn];
ll rev2;
struct Query{
int L,R,id,block;
bool operator < (const Query &p)const{//按照分块排序,再按照右端点排序
if(block == p.block) return R < p.R;
return block < p.block;
}
}Q[maxn];
ll res;
ll ans[maxn];
ll q_pow(ll a,ll b){
ll ans = 1;
while(b){
if(b & 1)
ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}//快速幂取模
ll C(int n,int k){
return fac[n] * inv[k] % mod * inv[n-k] % mod;
}//组合数公式
void init(){
rev2 = q_pow(2,mod-2);
fac[0] = fac[1] = 1;
for(int i = 2; i < maxn; i++){
fac[i] = i * fac[i-1] % mod;
}//预处理阶乘
inv[maxn-1] = q_pow(fac[maxn-1],mod-2);
for(int i = maxn-2; i >= 0; i--){
inv[i] = inv[i+1] * (i + 1) % mod;
}//预处理阶乘的逆元(很巧妙,不需要每次求逆元了)
}
inline void addN(int posL,int posR){//因为传进来的posL已经加1了,所以求S(posL,posR)=2S(posL-1,posR)-C(posL-1,posR)
//而S(posL-1,posR)就是上一次的结果res,故只需要算C(posL-1,posR)
res = (2 * res % mod - C(posL-1,posR) + mod) % mod;
}
inline void addM(int posL,int posR){//因为传进来的posR已经自增完成,res是上一次的结果S(posL,posR-1)故只需要求C(posL,posR)
res = (res + C(posL,posR)) % mod;
}
inline void delN(int posL,int posR){//因为传进来的是后缀自增,所以posL还是原来的值
//那么新的S(posL-1,posR)=(S(posL,posR)+C(posL-1,posR))/2,其中S(posL,posR)就是res
res = (res + C(posL-1,posR)) % mod * rev2 % mod;
}
inline void delM(int posL,int posR){//因为传进来的是后缀自增,所以posR还是原来的值
//那么新的S(posL,posR-1)=S(posL,posR)-C(posL,posR),其中S(posL,posR)就是res
res = (res - C(posL,posR) + mod) % mod;
}
int main(){
int T;
init();
int len = (int)sqrt(maxn*1.0);
scanf("%d",&T);
for(int i = 1; i <= T; i++){
scanf("%d%d",&Q[i].L,&Q[i].R);
Q[i].id = i;//记录下查询顺序编号
Q[i].block = Q[i].L / len;//块号
}
sort(Q+1,Q+1+T);//排序
res = 2;
int curL = 1,curR = 1;
for(int i = 1; i <= T; i++){
while(curL < Q[i].L) addN(++curL,curR);//需要算S(curL+1,curR)=2S(curL,curR)-C(curL,curR)
while(curR < Q[i].R) addM(curL,++curR);//需要算S(curL,curR+1)=S(curL,curR)+C(curL,curR+1)
while(curL > Q[i].L) delN(curL--,curR);//需要算S(curL-1,curR)=(S(curL,curR)+C(curL-1,curT))/2
while(curR > Q[i].R) delM(curL,curR--);//需要算S(curL,curR-1)=S(curL,curR)-C(curL,curR)
ans[Q[i].id] = res;
}
for(int i = 1; i <= T; i++){
printf("%lld\n",ans[i]);
}
return 0;
}
要命的是什么,有一支队伍由于失误,没能A掉这个题,他们明白算法且能够写出来,最后讨论的时候,他们疑惑:你们知道思路了,写不出来代码吗?当时很震惊,那么长的模板,,用一个数学公式写出来吗??,后来想想,我们不是会不会写模板的问题,是理不理解模板的运营过程以及这个模板是用来做什么的,我们都不清楚
以及一道非常遗憾的题目,取款机,很多人都A了,我们由于模板整理的不到位,思路什么的都是对的,只是最后一直没A出来,还是很可惜的。
莫名其妙就感冒了,,在从头学小蓝书,好好刷题,好好撸书,,