【规律题】Backward Digit Sums

2024-06-12 18:18
文章标签 backward 规律 sums digit

本文主要是介绍【规律题】Backward Digit Sums,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【POJ3187】【洛谷1118】Backward Digit Sums

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other)

Problem Description

FJ and his cows enjoy playing a mental game. They write down the numbers from 1 to N (1 <= N <= 10) in a certain order and then sum adjacent numbers to produce a new list with one fewer number. They repeat this until only a single number is left. For example, one instance of the game (when N=4) might go like this: 

    3   1   2   44   3   67   916

Behind FJ's back, the cows have started playing a more difficult game, in which they try to determine the starting sequence from only the final total and the number N. Unfortunately, the game is a bit above FJ's mental arithmetic capabilities. 

Write a program to help FJ play the game and keep up with the cows.

Input

Line 1: Two space-separated integers: N and the final sum.

Output

Line 1: An ordering of the integers 1..N that leads to the given sum. If there are multiple solutions, choose the one that is lexicographically least, i.e., that puts smaller numbers first.

Sample Input

4 16

Sample Output

3 1 2 4

题意:

我们会发现,这个规律是个倒杨辉三角。

写出一个 1 至 N的排列 a_i,然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少 1,直到只剩下一个数字位置。下面是一个例子:

3,1,2,4

4,3,6

7,9

16

最后得到 16 这样一个数字。

现在想要倒着玩这样一个游戏,如果知道 N,知道最后得到的数字的大小 sum,请你求出最初序列 a_i,为 1 至 N 的一个排列。若答案有多种可能,则输出字典序最小的那一个。

管理员注:本题描述有误,这里字典序指的是 1,2,3,4,5,6,7,8,9,10,11,12

而不是 1,10,11,12,2,3,4,5,6,7,8,9

分析:

思路

分析出来可以发现,题目给的要求的最后一位数字,实际上就是一个倒着的杨辉三角的权重分别乘以相应位置的数字后的和,可以通过STL里面的next_permutation按照字典序从小到大生成排列逐步生成数字序列,当得到第一个合乎要求的答案时输出此时的排列。

代码一:直接用next_permutation遍历(属于暴力了,HDU过了,洛谷TLE三个点) 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> vec;
int tri[20];
int jc(int n)
{int sum=1;for(int i=1;i<=n;i++)sum*=i;return sum;
}
int count(int n,int k)
{n--,k--;return jc(n)/(jc(k)*jc(n-k));
}
void tri_arr(int n)
{for(int i=1;i<=n;i++)tri[i-1]=count(n,i);
}
int main()
{int m,ans,countans=0;cin>>m>>ans;tri_arr(m);for(int i=1;i<=m;i++)vec.push_back(i);do{for(int i=1;i<=m;i++)countans+=vec[i-1]*tri[i-1];if(countans==ans) {cout<<vec[0];for(int i=1;i<m;i++)cout<<' '<<vec[i];cout<<endl;return 0;}countans=0;}while(next_permutation(vec.begin(),vec.end()));return 0;
}

代码二 优化版本(剪枝 跳过不可能排列段)

附惨痛的TLE

TLE四次之后某人突然想到,计算的半路上只要当前值大于目标值就不可能,可以直接跳过,高兴地拍桌子,改了之后,没过。。。。

然后又TLE了两次后想到。。。计算一个到一半就跳过这一个力度太小了,应该多跳几个,对哦,计算到一半就超过目标了,那后面爱咋排列咋排列与我有什么关系呢。于是根据next_permutation会从最小字典序到最大字典序的特性,我们直接让它从超过的位置为起始点直接进入最大字典序状态,下一次全排列就会跳过这些被判死刑了的排列。

        for(int i=1;i<=m;i++){countans+=vec[i-1]*tri[i-1];if(countans>ans) {sort(vec.begin()+i,vec.end(),cmp);flag=1;break;}}if(flag) continue;

通过sort实现部分字典序最大。

剪掉这部分枝之后就过了。emmmmmm

完整代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> vec;
int tri[12];
int jc(int n)
{int sum=1;for(int i=1;i<=n;i++)sum*=i;return sum;
}
int count(int n,int k)
{n--,k--;return jc(n)/(jc(k)*jc(n-k));
}
void tri_arr(int n)
{for(int i=1;i<=n;i++)tri[i-1]=count(n,i);
}
bool cmp(int a,int b){return a>b;}
int main()
{int m,ans,countans=0;bool flag=0;cin>>m>>ans;tri_arr(m);for(int i=1;i<=m;i++)vec.push_back(i);do{flag=0;countans=0;for(int i=1;i<=m;i++){countans+=vec[i-1]*tri[i-1];if(countans>ans) {sort(vec.begin()+i,vec.end(),cmp);flag=1;break;}}if(flag) continue;if(countans==ans) {cout<<vec[0];for(int i=1;i<m;i++)cout<<' '<<vec[i];cout<<endl;return 0;}}while(next_permutation(vec.begin(),vec.end()));return 0;
}

【代码三 DFS版本】

这个题本来就是个搜索题,,DFS才是正解,时间复杂度比全排列暴力要低很多。

#include <stdio.h>
int n,sum;
int visited[13]={0}; //防止重复
int ans[13]; //放置答案
int pc[12];//构造所有i C n-1
int dfs(int,int,int); //写函数原型是好习惯!
int main(){int i;scanf("%d%d",&n,&sum);//下面开始构造杨辉三角(即组合数表)pc[0]=pc[n-1]=1; //杨辉三角性质,两边都是1if (n>1)for (i=1;i*2<n;i++)pc[i]=pc[n-1-i]=(n-i)*pc[i-1]/i; //利用杨辉三角对称性和组合数公式计算if (dfs(0,-1,0)) //-1仅起占位符作用for (i=1;i<=n;i++)printf("%d ",ans[i]); //输出答案return 0;
}
int dfs(int i,int num,int v){ //参数说明:i表示正在搜索第i个数(从1开始),num表示第i个数是num,v表示前i个数的“和”为v
//返回值说明:返回0表示不行(不可能),返回1表示找到了可行解int j; //循环变量if (v>sum) //已经超了!return 0; //不可能if (i==n) //枚举到了最后一个,判断一下是否是可行解if (v==sum){ans[i]=num; //放置解return 1;}elsereturn 0;visited[num]=1;for (j=1;j<=n;j++){if (!visited[j] && dfs(i+1,j,v+pc[i]*j)){//v+pc[i]*j表示前(i+1)个数的“和”//已经找到了可行的解ans[i]=num;return 1;}}visited[num]=0;//一定记得复位return 0;//执行到这里一定是没有找到解
}

补充:有关杨辉三角的知识

  1. 每个数等于它上方两数之和。
  2. 每行数字左右对称,由1开始逐渐变大。
  3. 第n行的数字有n项。
  4. 第n行数字和为2n-1。
  5. 第n行的m个数可表示为 C(n-1,m-1),即为从n-1个不同元素中取m-1个元素的组合数。
  6. 第n行的第m个数和第n-m+1个数相等 ,为组合数性质之一。
  7. 每个数字等于上一行的左右两个数字之和。可用此性质写出整个杨辉三角。即第n+1行的第i个数等于第n行的第i-1个数和第i个数之和,这也是组合数的性质之一。即 C(n+1,i)=C(n,i)+C(n,i-1)。
  8. (a+b)n的展开式中的各项系数依次对应杨辉三角的第(n+1)行中的每一项。
  9. 将第2n+1行第1个数,跟第2n+2行第3个数、第2n+3行第5个数……连成一线,这些数的和是第4n+1个斐波那契数;将第2n行第2个数(n>1),跟第2n-1行第4个数、第2n-2行第6个数……这些数之和是第4n-2个斐波那契数。
  10. 将各行数字相排列,可得11的n-1(n为行数)次方:1=11^0; 11=11^1; 121=11^2……当n>5时会不符合这一条性质,此时应把第n行的最右面的数字"1"放在个位,然后把左面的一个数字的个位对齐到十位... ...,以此类推,把空位用“0”补齐,然后把所有的数加起来,得到的数正好是11的n-1次方。以n=11为例,第十一行的数为:1,10,45,120,210,252,210,120,45,10,1,结果为 25937424601=1110。

这篇关于【规律题】Backward Digit Sums的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1054970

相关文章

计蒜客 Half-consecutive Numbers 暴力打表找规律

The numbers 11, 33, 66, 1010, 1515, 2121, 2828, 3636, 4545 and t_i=\frac{1}{2}i(i+1)t​i​​=​2​​1​​i(i+1), are called half-consecutive. For given NN, find the smallest rr which is no smaller than NN

hdu 6198 dfs枚举找规律+矩阵乘法

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description We define a sequence  F : ⋅   F0=0,F1=1 ; ⋅   Fn=Fn

CF#284 (Div. 2) C.(几何规律)

题目链接:http://codeforces.com/contest/499/problem/C 解题思路: 把两个点的坐标分别带入方程组,如果最后两个值相乘为负,即异号,计数器++。其中有一个有趣的现象,从A到B的最短步数,可以变化为求A和B之间夹了多少条直线,那么最后只要求出直线数,即可求出最小步数。 如果一条直线夹在A和B中间,那么把A和B的坐标带入后,所得值相乘一定为负。数据很

HDU2524(规律推导)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2524 解题思路: 暴力推出矩阵,以n = 2 , m = 4为例: 1 3  6  10 3 9 18 30 可以发现第一行和第一列都是有规律的,彼此相差2、3、4·····,其他元素为相应行第一个元素乘以第一列元素的积。预处理之后,我们O(1)就可以输出g[n][m]的值。 另外,

HDU 1097 A hard puzzle(规律)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=1097 题意: 求a的b次方的最后一位。 题解: 直接从例子入手, 第一组数据 7 66,结果如下(只要最后一位所以模10) 7 9 3 1 7 9··· 循环节为4,即结果在4个数值内循环出现。 第二组数据 6 800,结果如下 6 6 6 6··· 循环节为1 ···

【科普知识】一体化电机掉电后“位置精准复位“机制与规律

在工业自动化、机器人技术及精密控制领域,电机作为核心执行元件,其稳定运行和精确控制对于整个系统的性能至关重要。 然而,电机在运行过程中可能会遭遇突然断电的情况,这会导致电机失去驱动力并停止在当前位置,甚至在某些情况下发生位置偏移。 因此,电机掉电后的位置恢复机制成为了一个关键技术问题。本文将探讨电机掉电后位置恢复的原理机制,以期为相关领域的研究与应用提供参考。 一、电机掉电后的位置偏移现象

密码(规律题)

链接: https://www.nowcoder.com/acm/contest/90/K 来源:牛客网 题目描述 ZiZi登录各种账号的时候,总是会忘记密码,所以他把密码都记录在一个记事本上。其中第一个密码就是牛客网的密码。 牛客网专注于程序员的学习、成长及职位发展,连接C端程序员及B端招聘方,通过IT笔试面试题库、在线社区、在线课程等提高候选人的求职效率,通过在线笔试

【SPOJ】Triple Sums【FFT】

传送门:【SPOJ】Triple Sums 题目分析: 首先我们不考虑 i<j<k i<j<k这个条件,构造多项式: Y=∑xai \qquad\qquad\qquad Y = \sum x^{a_i} 那么 ai+aj+ak=S ai+aj+ak=S的个数即 xai+aj+ak=S x^{a_i+a_j+a_k=S}的个数,等价于 Y3中xS Y^3中x^S的系数。 然后我们考虑容斥

事理图谱:事件演化的规律和模式

2016年7月,哈工大社会计算与信息检索研究中心(HIT-SCIR)开始启动事理图谱的研究工作。2017年10月,研究中心主任刘挺教授在中国计算机大会(CNCC)上正式提出事理图谱的概念。2018年9月,在研究中心丁效老师的主持下,研制出中文金融事理图谱1.0版本,2019年7月更新为2.0版。本文是对2016年7月以来工作的最新总结,敬请各位同行指正。 引言 事件是人类社会的核心概念之一,人

2014 Multi-University Training Contest 1/HDU4861_Couple doubi(数论/规律)

解题报告 两人轮流取球,大的人赢,,, 贴官方题解,,,反正我看不懂,,,先留着理解 关于费马小定理 关于原根 找规律找到的,,,sad,,, 很容易找到循环节为p-1,每一个循环节中有一个非零的球,所以只要判断有多少完整循环节,在判断奇偶,,, #include <iostream>#include <cstdio>#include <cstring>