A | 牛牛的DRB迷宫I |
链接:https://ac.nowcoder.com/acm/contest/3004/A
来源:牛客网
题目描述
牛牛有一个n*m的迷宫,对于迷宫中的每个格子都为'R','D','B'三种类型之一,'R'表示处于当前的格子时只能往右边走'D'表示处于当前的格子时只能往下边走,而'B'表示向右向下均可以走。
我们认为迷宫最左上角的坐标为(1,1),迷宫右下角的坐标为(n,m),除了每个格子有向右移动以及向下移动的限制之外,你也不能够走出迷宫的边界。
牛牛现在想要知道从左上角走到右下角不同种类的走法共有多少种,请你告诉牛牛从(1,1)节点移动到(n,m)节点共有多少种不同的移动序列,请你输出方案数对109+710^9+7109+7取余数后的结果。
我们认为两个移动序列是不同的,当且仅当移动序列的长度不同,或者在某一步中采取了不同的移动方式。
输入描述:
第一行输入两个正整数n,m(1≤n,m≤50)(1 \leq n,m \leq 50)(1≤n,m≤50)表示迷宫的大小是n行m列。
接下来n行,每行输入一个长度为m的字符串,字符串中仅包含大写字母'D','R','B'。
输出描述:
输出一行一个整数,表示方案数对109+710^9+7109+7取余数后的结果。
示例1
输入
复制5 5 RBBBR BBBBB BBBDB BDBBB RBBBB
5 5
RBBBR
BBBBB
BBBDB
BDBBB
RBBBB
输出
复制25
25
题解:dp题 判断如果这个为B那么状态就加上 dp【i-1】【j】和dp【i】【j-1】如果是这个字符为D 就加上dp【i】【j-1】
用递归会爆,然而我还是头铁试了试 确实爆了..
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char str[60][60];
ll n,m,sum=0;
ll a[60][60]={0};
const int mod=1e9+7;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
cin>>str[i][j];
}
}
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
if(i==1&&j==1)
{
a[i][j]=1;
}
if(str[i][j-1]=='B'||str[i][j-1]=='R')
{
a[i][j]+=a[i][j-1];
a[i][j]=a[i][j]%mod;
}
if(str[i-1][j]=='B'||str[i-1][j]=='D')
{
a[i][j]+=a[i-1][j];
a[i][j]=a[i][j]%mod;
}
}
}
cout<<a[n][m]%mod<<endl;
}
C | 牛牛的数组越位 |
链接:https://ac.nowcoder.com/acm/contest/3004/C
来源:牛客网
题目描述
牛牛写了这样一个C/C++程序:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[5][5];
a[-1][8]=12345;
printf("%d %d",a[1][-2],a[0][3]);
return 0;
}
他发现程序可以正常运行,并且输出为:
12345 12345
在C/C++中,这种数组越位行为是Undefined Behaviour(UB)的,也就是程序未定义行为,但是在牛牛的编译器呢,对于这种情况,二维数组的内存是连续的。
也就是说对于二维数组int a[5][5],在牛牛的电脑中是按照a[0][0],a[0][1],a[0][2],a[0][3],a[0][4],a[1][0]...a[1][4],a[2][0]...a[2][4],a[3][0]...a[4][4]
这样储存的。
牛牛所使用的编译器在寻址时是这样处理的,对于一个二维数组a[n][m],若对a[x][y]这个数组元素进行操作,最终访问到的地址为:a的首地址+m*x+y。
所以在寻址时,无论是a[-1][8]还是a[1][-2]最终在牛牛的电脑上使用该编译器编译出的程序均未发生非法访问的行为,他们最终都表示a[0][3]这个数组元素。
本题有T组测试数据。
牛牛先声明了一个n*m的int 型数组,即int a[n][m];,这个数组被他声明成一个全局变量,所以数组的初值全为0,接下来他要进行p次赋值运算。
每次他都选择一个二维下标x,y,并且把a[x][y]赋值成val。
当然,牛牛不会老老实实按照C语言的规范来写代码。
如果这p次赋值操作中不存在数组越位行为,则先输出n行,每行m个数。表示操作后的二维数组,数字之间用一个空格隔开,行末没有多余空格。然后输出一行"Accepted"(不含引号),表示正常运行。
如果这p次赋值操作中虽然存在数组越位行为但是没有发生非法访问,则先输出n行,每行m个数。表示操作后的二维数组,数字之间用一个空格隔开,行末没有多余空格。然后输出一行"Undefined Behaviour"(不含引号),表示虽然能够运行,但是牛牛的代码不规范存在隐患。
如果这p次赋值操作中出现了至少一次数组越位并且导致非法访问的行为,请输出一行一个字符串"Runtime error"(不含引号)。
输入描述:
第一行是一个正整数T(1≤T≤1000)(1 \leq T \leq 1000)(1≤T≤1000)表示测试样例的组数且保证∑n×m≤2×107且∑p≤2×107\sum n \times m \leq 2 \times 10^7且 \sum p \leq 2 \times 10^7∑n×m≤2×107且∑p≤2×107。对于每组案例:
第一行是三个正整数n,m,p(1≤n,m≤1000,0≤p≤10000)(1 \leq n,m \leq 1000,0 \leq p \leq 10000)(1≤n,m≤1000,0≤p≤10000)表示牛牛在全局中声明了一个int型的a数组,即int a[n][m];,接下来牛牛准备进行p次赋值操作。
接下来p行,每行三个整数x,y,val(−1000000≤x,y,val≤1000000)(-1000000 \leq x,y,val \leq 1000000)(−1000000≤x,y,val≤1000000)表示进行一次赋值操作,即a[x][y]=val;。
输出描述:
如果这p次赋值操作中不存在数组越位行为,则先输出n行,每行m个数。表示操作后的二维数组,数字之间用一个空格隔开,行末没有多余空格。然后输出一行"Accepted"(不含引号),表示正常运行。
如果这p次赋值操作中虽然存在数组越位行为但是没有发生非法访问,则先输出n行,每行m个数。表示操作后的二维数组,数字之间用一个空格隔开,行末没有多余空格。然后输出一行"Undefined Behaviour"(不含引号),表示虽然能够运行,但是牛牛的代码不规范,存在隐患。
如果这p次赋值操作中出现了至少一次数组越位并且导致非法访问的行为,请输出一行一个字符串"Runtime error"(不含引号)。
示例1
输入
复制4 2 4 8 -1 4 1 1 -3 2 2 -6 3 0 3 4 -1 8 5 -2 13 6 -100 406 7 100 -393 8 5 5 1 -1 8 1234 10 10 1 5 -51 1 1 1 1 0 0 7
4
2 4 8
-1 4 1
1 -3 2
2 -6 3
0 3 4
-1 8 5
-2 13 6
-100 406 7
100 -393 8
5 5 1
-1 8 1234
10 10 1
5 -51 1
1 1 1
0 0 7
输出
复制1 2 3 4 5 6 7 8 Undefined Behaviour 0 0 0 1234 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Undefined Behaviour Runtime error 7 Accepted
1 2 3 4
5 6 7 8
Undefined Behaviour
0 0 0 1234 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
Undefined Behaviour
Runtime error
7
Accepted
备注:
无论是否发生数组越位或者非法访问,输入数据都要完整读入。
题目中的代码不符合C/C++规范,在不同编译器中由于实现不同运行的结果也可能不同,请勿依赖特定编译器对于UB的实现。:)
题解:按照题目给的模拟就行了
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000005;
int maxsize,n,m,a[MAXN],T,x,y,val,p;
int hash1(int x,int y)
{
if(x*m+y>=maxsize||x*m+y<0)return -1;
return x*m+y;
}
bool flag1,flag2;
int main()
{
scanf("%d",&T);
while(T--)
{
flag1=true;
flag2=true;
scanf("%d %d %d",&n,&m,&p);
maxsize=n*m;
for(int i=0;i<maxsize;++i)a[i]=0;
while(p--)
{
scanf("%d %d %d",&x,&y,&val);
if(x>=n||y>=m||x<0||y<0)
{
flag2=false;
}
int pos=hash1(x,y);
if(~pos)
{
a[pos]=val;
}
else
{
flag1=false;
}
}
if(flag1)
{
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
printf("%d%c",a[hash1(i,j)],j==m-1?'\n':' ');
}
}
if(flag2)
{
printf("Accepted\n");
}
else
{
printf("Undefined Behaviour\n");
}
}
else
{
printf("Runtime error\n");
}
}
return 0;
}
D | 牛牛与二叉树的数组存储 |
链接:https://ac.nowcoder.com/acm/contest/3004/D
来源:牛客网
题目描述
树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样。树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可用树形象表示。树在计算机领域中也得到广泛应用,如在编译源程序时,可用树表示源源程序的语法结构。又如在数据库系统中,树型结构也是信息的重要组织形式之一。一切具有层次关系的问题都可用树来描述。满二叉树,完全二叉树,排序二叉树。
当一颗二叉树是满二叉树时,可以用如下的规则储存:
- 数组0下标不使用
- 节点i的左子节点在位置为(2*i);
- 节点i的右子节点在位置为(2*i+1);
- 节点i的父节点在位置为(i/2);
- 根节点被保存到数组下标为1的位置。
上图是一颗满二叉树,对于每个节点i,i*2是它的左子树,i*2+1是它的右子树,i/2则是它的父亲节点。
当然了,当树不为满二叉树的时候其实也能储存。
上图是树不为满二叉树的情况,我们先用一些虚点将其补充成一颗满二叉树。
根节点还是被储存到数组的第1个位置。
然后对于下标为i的节点,他的左孩子的下标为i*2,它的右孩子的下标为i*2+1,它的父亲节点的下标为i/2。
给你一个长度为n的数组,该数组储存了一颗二叉树,数组中仅含有-1和正整数,且整个数组中的正整数是从1到树尺寸连续的,不会出现如1,2,3,5,6,这种缺少4断掉的情况。
请你告诉我树的尺寸和根节点,并按照顺序打印每个节点的父亲节点、左孩子、右孩子分别是谁?
输入描述:
第一行是一个正整数n(1≤n≤105)(1 \leq n \leq 10^5)(1≤n≤105),表示数组的大小。
接下来一行n个整数,仅包含-1和正整数,如果输入的是-1,则表示该位置是空节点,反之则为节点编号。输入数据保证整个数组中节点编号是从1到树尺寸连续的。
输出描述:
对于每组案例:
首先在第一行输出:"The size of the tree is X",X表示树的尺寸,树的尺寸为二叉树中节点的数目。
接着在第二行输出:"Node X is the root node of the tree",X表示二叉树的根节点,也就是数组下标1的位置所储存的节点。
接下来输出size行,size表示树的尺寸。
每行格式为:"The father of node I is X, the left child is Y, and the right child is Z",I、X、Y、Z的含义为:第I个节点的父节点为X,它的左孩子为Y,它的右孩子为Z。
如果该节点是根节点,没有父亲节点,则X为-1。
如果该节点没有左孩子,则Y为-1。
如果该节点没有右孩子,则Z为-1。
示例1
输入
复制7 1 2 3 4 5 6 7
7
1 2 3 4 5 6 7
输出
复制The size of the tree is 7 Node 1 is the root node of the tree The father of node 1 is -1, the left child is 2, and the right child is 3 The father of node 2 is 1, the left child is 4, and the right child is 5 The father of node 3 is 1, the left child is 6, and the right child is 7 The father of node 4 is 2, the left child is -1, and the right child is -1 The father of node 5 is 2, the left child is -1, and the right child is -1 The father of node 6 is 3, the left child is -1, and the right child is -1 The father of node 7 is 3, the left child is -1, and the right child is -1
The size of the tree is 7
Node 1 is the root node of the tree
The father of node 1 is -1, the left child is 2, and the right child is 3
The father of node 2 is 1, the left child is 4, and the right child is 5
The father of node 3 is 1, the left child is 6, and the right child is 7
The father of node 4 is 2, the left child is -1, and the right child is -1
The father of node 5 is 2, the left child is -1, and the right child is -1
The father of node 6 is 3, the left child is -1, and the right child is -1
The father of node 7 is 3, the left child is -1, and the right child is -1
示例2
输入
复制7 3 -1 2 -1 -1 1 4
7
3 -1 2 -1 -1 1 4
输出
复制The size of the tree is 4 Node 3 is the root node of the tree The father of node 1 is 2, the left child is -1, and the right child is -1 The father of node 2 is 3, the left child is 1, and the right child is 4 The father of node 3 is -1, the left child is -1, and the right child is 2 The father of node 4 is 2, the left child is -1, and the right child is -1
The size of the tree is 4
Node 3 is the root node of the tree
The father of node 1 is 2, the left child is -1, and the right child is -1
The father of node 2 is 3, the left child is 1, and the right child is 4
The father of node 3 is -1, the left child is -1, and the right child is 2
The father of node 4 is 2, the left child is -1, and the right child is -1
备注:
温馨提示:为了避免PE,或者肉眼不可见的WA造成不必要的罚时,请使用牛客自带的自测调试功能
题解:根据题意进行模拟就行了。
代码如下:
#include <bits/stdc++.h>
#include <map>
using namespace std;
int a[100005];
int main()
{
int n;
while(~scanf("%d",&n))
{
map<int,int>m;
int cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]>0)
{
cnt++;
m[a[i]]=i;
}
}
printf("The size of the tree is %d\n",cnt);
printf("Node %d is the root node of the tree\n",a[1]);
for(int i=1;i<=cnt;i++)
{
printf("The father of node %d is %d,",i,m[i]/2==0?-1:a[m[i]/2]);
printf(" the left child is %d, and the right child is %d\n",m[i]*2>n?-1:a[m[i]*2],m[i]*2+1>n?-1:a[m[i]*2+1]);
}
}
}
F | 牛牛的Link Power I |
链接:https://ac.nowcoder.com/acm/contest/3004/F
来源:牛客网
题目描述
牛牛有一颗大小为n的神奇Link-Cut 数组,数组上的每一个节点都有两种状态,一种为link状态,另一种为cut状态。数组上任意一对处于link状态的无序点对(即(u,v)和(v,u)被认为是同一对)会产生dis(u,v)的link能量,dis(u,v)为数组上u到v的距离。
我们定义整个数组的Link能量为所有处于link状态的节点产生的link能量之和。
一开始数组上每个节点的状态将由一个长度大小为n的01串给出,'1'表示Link状态,'0'表示Cut状态。
牛牛想要知道整个数组的Link能量,为了避免这个数字过于庞大,你只用输出答案对109+710^9+7109+7取余后的结果即可。
输入描述:
第一行输入一个正整数n(1≤n≤105)(1 \leq n \leq 10^5)(1≤n≤105)
接下里一行输入一个长度大小为n的01串表示数组的初始状态,'1'表示Link状态,'0'表示Cut状态。
输出描述:
仅一行,表示整个数组的Link能量对109+710^9+7109+7取余后的结果。
示例1
输入
复制3 101
3
101
输出
复制2
2
示例2
输入
复制5 00110
5
00110
输出
复制1
1
示例3
输入
复制6 000010
6
000010
输出
复制0
0
题解:记录cnt与sum,cnt表示当前经过了多少个1,sum表示当前的贡献总和
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100005;
const long long mod=1e9+7;
char s[MAXN];
int n;
long long sum,cnt,ans;
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;++i)
{
sum=(sum+cnt)%mod;
if(s[i]=='1')
{
ans=(ans+sum)%mod;
++cnt;
}
}
printf("%lld\n",ans);
return 0;
}
H | 牛牛的k合因子数 |
链接:https://ac.nowcoder.com/acm/contest/3004/H
来源:牛客网
题目描述
合数是指自然数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。
牛牛最近在研究“k合因子数”,所谓“k合数”是指一个数的所有因子中,是合数的因子共有k个。
例如20的因子有1,2,4,5,10,20,其中4,10,20为合数,它有3个合数因子,就称20是一个 “3合因子数”
牛牛想要知道1~n中给定k的情况下k合因子数的数目。
输入描述:
第一行输入两个数字n,m(1≤n,m≤105)(1 \leq n,m \leq 10^5)(1≤n,m≤105)表示范围以及查询“k”的数目
接下来m行,每行一个正整数k(1≤k≤n)(1 \leq k \leq n)(1≤k≤n)查询k合因子数的数目。
输出描述:
一行一个数字,表示k合因子数的数目
示例1
输入
复制10 5 1 2 3 4 5
10 5
1
2
3
4
5
输出
复制4 1 0 0 0
4
1
0
0
0
说明
1~10的范围内
1合因子数有:4,6,9,10,共4个
2合因子数有:8,共1一个
题解:这一题用素数筛选法,然后就根据题目一个一个进行判断,代码如下;
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char str[60][60];
const int mod=1e9+7;
bool visit[250000+10];//用来判断素数
ll prime[250000+10];//存储素数
void is_prime(){
int cnt=0;
memset(visit,true,150000);//全部初始化为素数
for(ll i=2;i<150000;i++)//从0开始去除掉所有的素数的倍数
if(visit[i]){//如果是素数,那么这个素数的倍数一定不是素数。
prime[cnt++]=i;//是素数就送入prime数组中。
for(ll j=2*i;j<150000;j=j+i)
visit[j]=false;
}
/*visit[0]=false;visit[1]=false;//0和1都不是素数。 */
}
ll pp(ll x)
{
ll sum=0;
for(int i=1;i<=sqrt(x);i++)
{
if(x%i==0)
{
if(visit[i]==false)
sum++;
if(i!=sqrt(x)&&visit[x/i]==false)
sum++;
}
}
return sum;
}
ll a[1500000+100],b[1500000+10];
int main()
{
ll n,m;
is_prime();
cin>>n>>m;
for(ll i=0;i<m;i++)
{
cin>>b[i];
}
for(ll i=1;i<=n;i++)
{
a[pp(i)]++;
}
for(ll i=0;i<m;i++)
{
cout<<a[b[i]]<<endl;
}
return 0;
}