您的位置:首页 > 其它

牛客练习赛13题目题解

2018-03-17 18:55 501 查看
A-幸运数字I/*******************************************************
Data: 2017/3/16 19:19:10
Author: Wen Yaxin

解题思路:水题,统计字符'4'和字符'7'的个数即可。

变量含义:
str:存放输入的字符串
**********************************************************/
#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;

char str[100];
int main() {
while(~scanf("%s",str)) {
int four = 0;
int seven = 0;
for(int i = 0; i < (int)strlen(str); i++) {
if(str[i]=='4') {
four++;
}
if(str[i]=='7') {
seven++;
}
}
if(four==0 && seven==0) {
printf("-1\n");
}
else {
if(four>=seven) {
printf("4\n");
}
else {
printf("7\n");
}
}
}
return 0;
}
B-幸运数字II/*******************************************************************************
Data: 2018-03-16 20:11:44
Author: Wen Yaxin

解题思路:首先使用dfs求解出所有的幸运数字,题目给出
数字数据范围为10亿,则最多10位由4和7组成的数字就是
极限,对于每一位,可以是4,也可以是7,用递归进行计算,
并保留所有的中间结果,一次递归的过程求出所有幸运数字。
大概有一千多个,然后对他们进行排序,则对于给出的L,R,
可以知道两个相邻幸运数字间的那些数字都对答案贡献较小
的那个幸运数字,就这样跳着求。只要求出大于等于L幸运数
字的位置,之后便不用查找,通过自增得来就可以了。

变量含义:
cnt:t数组的变量,在存储幸运数字时使用
t:t数组用来存储所有的幸运数字

方法含义:
dfs:递归求幸运数字,dfs(x,num)x代表当前这位是x
getNext:使用二分查找第一个大于等于i的幸运数字的位置
***************************************************************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const long long maxn = 4444444444;
long long cnt,t[1000];
void dfs(int x,long long num) {
num = num*10 + x;
if(num > maxn) {
return;
}
t[cnt++] = num; //存储中间的每一个数
dfs(4,num);
dfs(7,num);
}
int getNext(long long i){
int pos = lower_bound(t,t+cnt,i)-t;
return pos;
}
int main() {
cnt = 0;
dfs(4,(long long)0);
dfs(7,(long long)0);
//printf("%d\n",cnt);
sort(t,t+cnt); //排序,二分查找要求数组元素有序
long long L,R,temp;
while(~scanf("%lld%lld",&L,&R)) {
//防止L>R的情况,但本题此判断无用,因为题目说了L<=R
if(L>R) {
temp = L;
L = R;
R = temp;
}
long long ans = 0;
long long i = L;
long long x;
long long j = getNext(i); //求起始位置。
while(true) {
x = t[j];
if(x >= R) {
ans += (R-i+1)*x;
break;
}
ans += (x-i+1)*x;
i = x+1;
j++;
}
printf("%lld\n",ans);
}
return 0;
}
C-幸运数字III/**********************************************************************
Data: 2018-03-16 21:15:54
Author: Wen Yaxin

解题思路:题目K很大,一次次的变换,对于题目给出的1秒时间显然是
不可能过的。则根据题目分析如下。
1.最早出现47的地方,如果47后面有7,则此时出现序列477,如果4是第
奇数个字符,则一次变换后,序列为447,再次出现47,4是第偶数个字符,
变换后变成477。由此可知,出现477(且其里面的47是串里面最左侧的47),
对于剩余变换次数,如果是奇数,最终中间位为4,否则不变,遇到这种情况
不论还有多少次变换,只要确定变换次数的奇偶即可确定答案。

2.最早出现47的地方,如果47前面有4,则此时出现序列447,如果47中的4
是第偶数位字符,则变换一次,序列变成477,则再次变换一次,序列变成447.
可以发现,出现447(且其里面的47是串里面最左侧的47),对于剩余变换次数,
是奇数次,则中间的4最终为7,否则不变。遇到这种情况不论还有多少次变换,
只要确定变换次数的奇偶即可确定答案。

3.不是1,2两种情况,只是单纯找到了47,如果4是第奇数个字符,则47 -> 44.
下一次考虑47就要从后一个4开始检测了。

4.如果4是第偶数个字符,则47->77,则检测位置需要从4左侧的位置开始。

5.当串中没有47的时候,无论还剩余多少次变换都是无用的,应立即结束。

变量含义:
str:存放题目给出的字符串
******************************************************************************/
#include <iostream>
#include <stdio.h>
#include <string>

using namespace std;

int n,k,temp;
char str[1000000];
int main() {
while(~scanf("%d%d",&n,&k)) {
scanf("%s",str);
//变换0次,直接输出。
if(k == 0) {
puts(str);
}
else {
for(int i = 0; i < n-1; i++) {
//遇到47组合。
if(str[i]=='4' && str[i+1]=='7') {
//遇到477组合
if(i+2<n && str[i+2]=='7') {
temp = i+1;
//4是第奇数个字符
if(temp%2==1) {
if(k%2==1) {
str[i+1] = '4';
}
k = 0;
}
}
if(!k) break;
//遇到447的组合。
if(i-1>=0 && str[i-1]=='4') {
temp = i+1;
//中间的4是第偶数个字符
if(temp%2==0) {
if(k%2) {
str[i] = '7';
}
k = 0;
}
}
if(!k) break;
temp = i+1;
//是第奇数个字符。
if(temp%2) {
str[i+1] = '4';
k--; //剩余变换次数-1
}
else {
str[i] = '7';
k--;
i = i-2;
/*i=i-2是因为,下次循环位置要从i-1开始,
由于for循环中i会自增,所有让i减去2,再
自增1,即下次循环从i-1开始。*/
}
if(!k) break;
}
}
puts(str);
}
}
return 0;
}
D-幸运数字IV/*******************************************************************************************
Date 2018/3/17 17:47
Author Wen Yaxin

解题思路:1~n,n个数的全排列有n!种。13的阶乘已经大于10亿。
10亿是题中给出最大的数据.
1.如果第k小全排列不存在,直接输出-1。
2.则题目转换成求:[max(1,n-12),n]的第k小全排列。
则对于max(1,n-12)-1>=1的前提下,我们求1~max(1,n-12)-1中有
多少个luckyNumer,然后在看[max(1,n-12),n]种有多少个luckyNumer
其下标也是luckyNumer。两个值相加。

常量含义:
maxn:大于10亿的第一个幸运数字

变量含义:
fac:fac[i]存放i的阶乘
n,k:题目给出的数据放在n,k
t:用来存储所有的幸运个数字
arr:用来存放需要求全排列的序列
b:arr数组得第k小排列,存放在b中
cnt:作为t数组的下标
Start:起始数字
End:终止数字

方法含义:
calFac:计算阶乘
dfs(int x,long long num):递归求解所有幸运数字,x代表当前位取4还是取7,num是上一步的值
fun(long long x):该方法查找t数组并返回第一个大于等于x的幸运数字在t数组的下标
init:完成初始化工作
kth_permuation(rest,le,num):求arr数组中存放序列的第k小全排列。rest是剩余多少个数字。
le每确定一个位置上的数字,le--.num第num小排列。
isLuckyNum:判断某个数字是否幸运数字

测试数据:
输入:
100000000 100000
95729374 39579283745
10 10000000
10 1324346
9357 35738945
1000000000 1000000000
1324324 54678574
44774480 464817709
输出:
510
-1
-1
0
30
1022
126
306
***************************************************************************************/
#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;

const long long maxn = 4444444444;
long long fac[20],n,k,t[2000],arr[20],b[20];
int cnt,len;
long long Start,End;
//计算阶乘
void calFac() {
fac[0] = 1;
for(int i = 1; i <= 14; i++) {
fac[i] = fac[i-1]*i;
}
}
void dfs(int x,long long num) {
num = num*10 + x;
if(num > maxn) {
return;
}
t[cnt++] = num;
dfs(4,num);
dfs(7,num);
}
int fun(long long x) {
int pos = lower_bound(t,t+cnt,x)-t;
return pos;
}
void init() {
calFac();
cnt = 0;
dfs(4,(long long)0);
dfs(7,(long long)0);
sort(t,t+cnt);
}
//求第k小全排列。
void kth_permuation(int rest,int le,long long num) {
int pos = 0;
while(le) {
for(int i = 0; i < len; i++) {
if(num <= fac[rest]) {
b[pos++] = arr[i];
arr[i] = maxn;
rest--;
sort(arr,arr+le);
break;
}
else {
num = num-fac[rest];
}
}
le--;
}
}
//判断是否luckyNum
bool isLuckyNum(long long num) {
while(num) {
if(num%10!=4 && num%10!=7) return false;
num = num/(long long)10;
}
return true;
}
int main() {
init();
while(~scanf("%lld%lld",&n,&k)) {
int temp = min(n,(long long)13);
if(k > fac[temp]) {
printf("-1\n");
}
else {
End = n;
Start = max((long long)1,End-12);
len = End-Start+1;
for(int i = 0; i < len; i++) {
arr[i] = Start+(long long)i;
}
kth_permuation(len-1,len,k);
int ans = 0;
temp = fun(Start-1);
if(t[temp]==Start-1) {
ans = temp+1;
}
else {
ans = temp;
}
for(int i = 0; i < len; i++) {
if(isLuckyNum(b[i])) {
if(isLuckyNum(Start+i)) {
ans++;
}
}
}
printf("%d\n",ans);
}
}
return 0;
}

E-乌龟跑步/********************************************************************************
Date 2018/3/18 11:17
Author Wen Yaxin

解题思路:这个题目是4维的DP,没想出来,看别人的思路。
dp[i][j][k][status] 前i个字符,改变j次,是否能到达k位置,且其朝向是status。
**********************************************************************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>

using namespace std;

int dp[110][55][220][5]; //dp[i][j][k][status] 前i个字符,改变j次,是否能到达距源点k的地方,并且朝向是status.
char str[120];
int main() {
int n;
while(~scanf("%s",str+1)) {
scanf("%d",&n);
int len = strlen(str+1);
memset(dp,0,sizeof(dp));
dp[0][0][100][1] = 1; //把负坐标轴抵消掉,则源点放在x=100的位置,
for(int i = 1; i <= len; i++) {
for(int j = 0; j <= n; j++) {
for(int k = 0; k <= 200; k++) {
//注意下面的运算都是或运算。a |= b -> a = a|b
//当前指令是向前走
if(str[i]=='F') {
//还有转换次数,F->T,不讨论朝向,两个方向均考虑
if(j) dp[i][j][k][1] |= dp[i-1][j-1][k][0]; //右转左
if(j) dp[i][j][k][0] |= dp[i-1][j-1][k][1]; //左转右
//直走的情况
dp[i][j][k+1][1] |= dp[i-1][j][k][1];
dp[i][j][k-1][0] |= dp[i-1][j][k][0];
}
else {
//T->F,反转变成直走
if(j) dp[i][j][k+1][1] |= dp[i-1][j-1][k][1];
if(j) dp[i][j][k-1][0] |= dp[i-1][j-1][k][0];
//反转
dp[i][j][k][1] |= dp[i-1][j][k][0];
dp[i][j][k][0] |= dp[i-1][j][k][1];
}
}
}
}
int ans = 0;
for(int i = 0; i <= 200; i++) {
if(dp[len]
[i][1]) ans = max(ans,abs(100-i));
if(dp[len]
[i][0]) ans = max(ans,abs(100-i));
}
printf("%d\n",ans);
}
return 0;
}


F-m皇后/*********************************************************************************
Date 2018/3/18 10:22
Author Wen Yaxin

解题思路:存储一个点的横纵坐标x,y以及x-y,x+y
的值。对于x,y,我们可以由此判断皇后们是否处于同行或同列。
而x-y和x+y可以判断皇后是否处于同一斜线。
如果皇后(x1,y1) (x2,y2)处于同一斜线。

则斜率可以是1,也可以是-1.(题目说了不会有两个皇后在同一位置)
(1)斜率为1:y2-y1/(x2-x1) = 1 --> y2-y1=x2-x1 --> x1-y1 = x2-y2
所以对于x1-y1 = x2-y2的点,可以判断他们处于西南-东北方向的斜线上

(2)斜率为-1:y2-y1/(x2-x1) = -1 --> y2-y1=x1-x2 --> x1+y1 = x2+y2
所欲对于x1+y1 = x2+y2的点,可以判断他们处于西北-东南方向的斜线上。

变量含义:
node:维护皇后的横坐标,纵坐标,横纵坐标和,横纵坐标差,和不安全方向数

方法含义:
cmp1:按照横坐标排序,横坐标相同时使纵坐标从小到大排序,用来处理处于同一行的皇后
cmp2:按照纵坐标排序,纵坐标相同时按横坐标从低到高排序,用来处理处于同一列的皇后
cmp3:按照x-y排序,x-y相同时,按x+y从小到大排序,用来处理从西南->东北方向的皇后
cmp4:按照x+y排序,x+y相同时,按x-y从小到大排序,用来处理从西北->东南方向的皇后
*********************************************************************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int maxn = 1e5+10;
int ans[10];
struct Node {
int r; //行号
int c; //列号
int p;
int q;
int num;
}node[maxn];
//使同行的皇后,按照纵坐标从小到大排列
bool cmp1(Node a,Node b) {
if(a.r == b.r) return a.c < b.c;
return a.r < b.r;
}
//使同列的皇后,按照横坐标从小到大排列
bool cmp2(Node a,Node b) {
if(a.c == b.c) return a.r < b.r;
return a.c < b.c;
}
//使处于东北-西南方向的皇后,
bool cmp3(Node a,Node b) {
if(a.p == b.p) return a.q<b.q;
return a.p < b.p;
}
bool cmp4(Node a,Node b) {
if(a.q == b.q) return a.p<b.p;
return a.q < b.q;
}
int main() {
int n,m,x,y;
while(~scanf("%d%d",&n,&m)) {
for(int i = 0; i < m; i++) {
scanf("%d%d",&x,&y);
node[i].r = x;
node[i].c = y;
node[i].p = x - y;
node[i].q = x + y;
node[i].num = 0;
}
//对同行的皇后进行处理
sort(node,node+m,cmp1);
for(int i = 0; i < m-1; i++) {
if(node[i].r == node[i+1].r) {
node[i].num++; //右侧不安全
node[i+1].num++; //左侧不安全
}
}
//对处于同列的皇后进行处理
sort(node,node+m,cmp2);
for(int i = 0; i < m-1; i++) {
if(node[i].c == node[i+1].c) {
node[i].num++; //上侧不安全
node[i+1].num++;//下侧不安全
}
}
sort(node,node+m,cmp3);
for(int i = 0; i < m-1; i++) {
if(node[i].p == node[i+1].p) {
node[i].num++;
node[i+1].num++;
}
}
sort(node,node+m,cmp4);
for(int i = 0; i < m-1; i++) {
if(node[i].q == node[i+1].q) {
node[i].num++;
node[i+1].num++;
}
}
memset(ans,0,sizeof(ans));
for(int i = 0; i < m; i++) {
ans[node[i].num]++;
}
for(int i = 0; i <= 8; i++) {
printf("%d",ans[i]);
if(i != 8) {
printf(" ");
}
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: