问题 A: 组合数
题目描述
求组合数C(N,M),以及C(N,M)因子个数。
输入
N和M,其中0<=M<=N<=50,以EOF结束。
输出
该组合数结果
样例输入 Copy
3 2 4 2
样例输出 Copy
3 2 6 4
思路: 1.C(N,M) (0<=M<=N<=50)可以选择打表
2.由于数据较大,普通的求因子个数算法肯定超时,这时可以考虑质因子分解算法求因子个数
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const int Max=60;
typedef long long LL;
LL C[Max][Max];
void Init()
{
for(int i=0;i<=50;i++)
{
C[0][i]=0;
C[i][0]=1;
}
for(int i=1;i<=50;i++)
{
for(int c=1;c<=50;c++)
{
C[i][c]=C[i-1][c]+C[i-1][c-1];
}
}
return ;
}
int factor(LL x)
{
int n=1;
for(LL i=2;i<=x;i++)
{
if(x%i==0)
{
int c=0;
while(x%i==0)
{
x/=i;
c+=1;
}
n*=(1+c);
}
if(x<i) break;
}
return n;
}
int main()
{
int N,M;
Init();
while(~scanf("%d %d",&N,&M))
{
printf("%lld %d\n",C[N][M],factor(C[N][M]));
}
return 0;
}
问题 C: 序列交换
题目描述
给一个 1 到 n 的排列,每次可以交换相邻两个数,问使用最少操作次数使得序列递增的方案是否唯一。
输入
多组输入,每组一个数n(1<=n<=10^5),然后是一个1~n的排列。
输出
方案唯一输出Yes,否则输出No。
样例输入
1
2
2 1
3
3 2 1
样例输出
Yes
No
思路:题目所问的是否存在唯一的最少操作次数方案 ,其实可以发现只要对一个序列操作次数>=2时便不存在唯一情况
再转换一下,若序列存在一个最长递增子序列且长度>=N-1时,是符合要求的
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int Max=1e5+5;
vector<int> v;
int main()
{
int N,Arr[Max];
while(~scanf("%d",&N))
{
for(int i=0;i<N;i++){
scanf("%d",&Arr[i]);
}
for(int i=0;i<N;i++){
if(v.empty()||Arr[i]>v[v.size()-1])
v.push_back(Arr[i]);
else
{
int index=upper_bound(v.begin(),v.end(),Arr[i])-v.begin();
v[index]=Arr[i];
}
}
if(v.size()>=N-1)
printf("Yes\n");
else
printf("No\n");
v.clear();
}
return 0;
}
问题 E: Jack的A+B
题目描述
现在有整数a,b,请按西方数字数量级方式输出a+b
输入
题目有多组测试数据
每组输入两个整数a,b
(0<=a,b<=10000000)
输出
输出西方数字数量级的a+b
样例输入 Copy
999 1 36 30 100000 100
样例输出 Copy
1,000 66 100,100
提示
输出的数从最低位起,每三位用逗号隔开
思路: 唯一的问题就是控制符号','的输出,找一下规律就好了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
int x,y,z,n;
while(~scanf("%d %d",&x,&y))
{
z=x+y;
if(z==0)
{
printf("0\n");
continue;
}
char str[20];
n=0;
while(z)
{
str[n]=z%10+'0';
z/=10;
n+=1;
}
str[n]='\0';
int Tag=1;
for(int i=n-1;i>=0;i--)
{
printf("%c",str[i]);
if(i!=0&&(n-Tag)%3==0)
printf(",");
Tag+=1;
}
printf("\n");
}
return 0;
}
问题 G: 圆桌上的晚餐
题目描述
大家一定在圆桌上吃过饭了,现在问题很简单,n个人坐在一个圆桌旁,其中有一些人是吃饱了的。那么当服务员端菜到某个人面前的时候,如果这个人吃饱了的话,那么这个人就会进行‘战术谦让’把菜端到下一个人的面前,如此反复直到这个菜遇到还没有吃饱的人的面前的时候,这个菜就会被吃掉。那么这个菜到底会被哪个人吃掉呢。
输入
输入有多组数据 每组数据第一行有一个n,表示有n个人(1<= n <=1000)
第二行有一个m表示菜会被端到第m个人面前(1<= m <= n)
第三行有n个数字表示每个人的状态0表示还没有吃饱,1表示已经吃饱了
(编号从1开始,第n个人下一个人是第一个人)
输出
输出最终吃掉这个菜的人的编号答案一定存在
样例输入 Copy
5 5 0 0 0 0 1 5 3 1 0 1 1 1
样例输出 Copy
1 2
思路: 循环找0
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
int N,M,p[1005];
while(~scanf("%d %d",&N,&M))
{
for(int i=1;i<=N;i++){
scanf("%d",&p[i]);
}
while(p[M]!=0)
{
M+=1;
if(M>N)
M-=N;
}
printf("%d\n",M);
}
return 0;
}
问题 I: 夫子云游
题目描述
改编自猫腻所著的同名小说《将夜》目前正在火热开播,其中男主角宁缺在考书院二层楼时遇一题“那年春,夫子出国游历,遇桃山美酒,遂寻径登山赏桃品酒,一路摘花饮酒而行,始斩一斤桃花,饮一壶酒,后夫子惜酒,故再斩一斤桃花,只饮半壶酒,再斩一斤桃花,饮半半壶酒,如是而行……至山顶,夫子囊中酒尽,惘然四顾,问:夫子一共斩了几斤桃花,饮了几壶酒?”而当我们的男主角宁缺看到这道题目时,更是直接来了句“谁出的这道题,太二了”,紧接着就提笔写下了“夫子饮二壶酒,斩尽满山桃花”后直接就交卷走人了赢得书院弟子的大赞。
今夫子再次游历,他提着酒壶,从出院出来,酒壶中有酒2斗,他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店M(0<M<=10)次,遇到花N(0<M<=10)次,已知最后一次遇到的是花,他正好把酒喝光了。
请计算夫子遇到店和花的合理的次序种数。
可以把遇店记为a,遇花记为b,如果M=5,N=10。则:babaabbabbabbbb 就是合理的次序之一。
输入
M、N 分别为遇到店和花的次数
输出
所有可能店和花次序方案的个数
样例输入 Copy
5 10
样例输出 Copy
14
思路:DFS找合理次序,每次搜索无非两种情况 1.遇店 2.遇花
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
int M,N,re;
void DFS(int x,int y,int z)
{
if(x<=0||x>z)
return ;
if(x==1)
{
if(y==0&&z==1)
{
re+=1;
return ;
}
}
DFS(x-1,y,z-1);
DFS(2*x,y-1,z);
return ;
}
int main()
{
while(~scanf("%d %d",&M,&N))
{
re=0;
DFS(2,M,N);
printf("%d\n",re);
}
return 0;
}
问题 J: 老肖数等式
题目描述
老肖前几年当了小学数学老师,他每天都会布置一次题目,他布置题目有个习惯,他只布置两个数的加法,两个数都不超过100,而且会让所有的题目答案都是一样的,所以这真的是一个奇怪的数学老师呢,他又有点想偷点懒,想你帮他做个自动出试卷的程序,你能帮他解决这个问题吗?
输入
多组输入,每行输入一个数x作为等式答案(0<=x<=200)
输出
每行输出一个等式,等式里的两个数a,b(0<=a,b<=100)
样例输入 Copy
5 3
样例输出 Copy
1. 0+5= 2. 1+4= 3. 2+3= 1. 0+3= 2. 1+2=
思路:唯一要注意的就是已出现过的a,b不会再以b,a的形式出现
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
int x;
while(~scanf("%d",&x))
{
for(int i=0;i<=x/2;i++)
{
printf("%d. %d+%d=\n",i+1,i,x-i);
}
}
return 0;
}
问题 K: WaWa的难题
题目描述
HaHa和WaWa是好朋友,他们在临近期末的这段时间一起宅在图书馆学习。
今天HaHa在书上看到一个排列组合题目,思考很久后,仍然找不出其中的规律。
于是他把题目叙述给了WaWa。
题目:
————————————————————————
一个长度为N的排列,由数字1~N组成,它满足两个条件。
1、数字1永远在第一位。
2、任意两个相邻数字之差小于等于2。
现在给出一个N,
你能知道能组成多少个符合条件的排列吗?。
例如:
N=4
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
所以答案为4
————————————————————————
WaWa听后也是一脸懵逼。
现在WaWa想求助于你们,WaWa给出一个正整数N,问你用1~N能组成多少个符合题意的排列。
输入
多组数据。
每组数据输入一个正整数N(1<=N<=100)。
输出
输出符合题意的排列个数
样例输入 Copy
2 4
样例输出 Copy
1 4
思路:通过DFS找出N=i(i<=12)的次序数,然后就是艰难的找规律过程
规律:N[i]=N[i-1]+N[i-3]+1
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
LL Arr[200]={0,1,1,2,4,6,9};
void Deal()
{
for(int i=7;i<=100;i++)
{
Arr[i]=Arr[i-3]+Arr[i-1]+1;
}
}
int main()
{
int N;
Deal();
while(~scanf("%d",&N))
{
printf("%lld\n",Arr[N]);
}
return 0;
}
问题 M: 最亲密的x个人
题目描述
有一天,地球受到了降维打击,从三维变成了一维。从此我们都生活在一条线上,给这条线加上坐标,每个点都是大于等于 0 的正整数。
有一天小明突发奇想,想知道谁是他最亲密的人,距离小明越近的人和小明越亲密。
假设有 N 个人,每个人的编号为 i(1 <= i <= N ),坐标为 ki(k[i-1] <= k[i] <= k[i+1]),小明的坐标为 M(小明是 N 个人中的一个),你们可以帮助小明找到他最亲密的 X个人的编号吗?
输入
多组输入
对于每组数据,第一行为三个整数N(0<N<=100000 )、M(0<M<=100000000)、X(X <= N && X <= 100)
第二行有N个数,分别表示 N 个人的坐标
输出
小明最亲密的 X 个人的编号(亲密度相同的,按id从小到大输出。如果第 x+1 个人和第 x 个人一样亲密,也需要输出)
样例输入 Copy
3 2 1 1 2 4 3 2 1 1 2 3
样例输出 Copy
1 1 3
思路:按亲密度排序
注意一种情况:如果第 x+1 个人和第 x 个人一样亲密,也需要输出
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int Max=1e5+5;
struct node{
int x;
int y;
int z;
}c[Max];
bool Compare(node u,node v)
{
if(u.z==v.z)
return u.y<v.y;
return u.z<v.z;
}
int main()
{
int N,M,X;
while(~scanf("%d %d %d",&N,&M,&X))
{
for(int i=1;i<=N;i++)
{
scanf("%d",&c[i].x); //坐标
c[i].y=i; //编号
c[i].z=fabs(M-c[i].x); //亲密度
}
sort(c+1,c+N+1,Compare);
for(int i=2;i<=X+1;i++)
{
printf("%d\n",c[i].y);
}
if(c[X+1].z==c[X+2].z)
printf("%d\n",c[X+2].y);
}
return 0;
}