算法日志篇 week3


B - 求平均年龄 OpenJ_Bailian - 2714

#include <bits/stdc++.h>
using namespace std;
void solve(){
    int n;
    cin >> n;
    float res = 0;
    for(int i =0;i < n;i ++){
        float t;
        cin >> t;
        res += t;
    }
    printf("%.2f",res / n);
}
int main(){
    solve();
    return 0;
}

题解
简单的求平均值问题。

C - 判断闰年 OpenJ_Bailian - 2733

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n;
    cin >> n;
    if(n % 4 == 0){
        if(n % 100 == 0 && n % 400 != 0)cout << "N\n";
        else if(n % 3200 == 0)cout << "N\n";
        else cout << "Y\n";
    }else{
        cout << "N\n";
    }
}
int main(){
    solve();
    return 0;
}

题解
公历纪年法中,能被4整除的大多是闰年,但能被100整除而不能被400整除的年份不是闰年, 能被3200整除的也不是闰年,如1900年是平年,2000年是闰年,3200年不是闰年。

D - 波兰表达式 OpenJ_Bailian - 2694

波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的波兰表示法为+ 2 3。波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的波兰表示法为* + 2 3 4。本题求解波兰表达式的值,其中运算符包括+ - * /四个。

#include<bits/stdc++.h>
using namespace std;
double solve(){
    char s[20];
	cin >> s;
	switch(s[0]) { 
		case '+':  return solve() + solve(); 
		case '-':  return solve() - solve(); 
		case '*':  return solve() * solve(); 
		case '/':  return solve() / solve(); 
		default:   return stod(s); 
		break; 
	} 
}
int main()
{
	printf("%lf",solve());
	return 0;
}

E - 最大公约数 OpenJ_Bailian - 3248

给定两个正整数,求它们的最大公约数。

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int x,y;
    while(cin >> x >> y){
        while(x != y){
            if(x > y){
                x = x - y;
            }else{
                y = y - x;
            }
        }
        cout << x << "\n";
    }
}
int main(){
    solve();
}

题解
使用辗转相除法来求出最大公约数。

F - 1的个数 OpenJ_Bailian - 3708

给定一个十进制整数N,求其对应2进制数中1的个数

#include<bits/stdc++.h>
using namespace std;
void solve(){
    long long x;
    int count = 1;
    cin >> x;
    if(x == 0)cout << 0 <<"\n";
    else{
        while(x / 2 >= 1){
        if(x % 2 == 1){
            count ++;
            x = x / 2;
        }else{
            x = x / 2;
        }
        }
        cout << count << "\n";
    }
}
int main(){
    int n;
    cin >> n;
    while(n --){
        solve();
    }
}

题解
将数换算为2进制的计算方式。依次求出每一个位数是0还是1。如果是1则加一如果是0则继续进行除法操作。

G - 计算鞍点 OpenJ_Bailian - 3670

给定一个5*5的矩阵,每行只有一个最大值,每列只有一个最小值,寻找这个矩阵的鞍点。
鞍点指的是矩阵中的一个元素,它是所在行的最大值,并且是所在列的最小值。
例如:在下面的例子中(第4行第1列的元素就是鞍点,值为8 )。
11 3 5 6 9
12 4 7 8 10
10 5 6 9 11
8 6 4 7 2
15 10 11 20 25

#include <bits/stdc++.h>
using namespace std;
int sz[5][5];
int main() {
    int x = 1;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            cin >> sz[i][j];
        }
    }
    for (int i = 0; i < 5; i++) {
        int max = sz[i][0];
        int mi = i, mj = 0;
        for (int j = 0; j < 5; j++) {
            if (sz[i][j] >= max) {
                max = sz[i][j];
                mj = j;
            }
        }
        int k;
        for (k = 0; k < 5; k++) {
            if (sz[k][mj] < max) break;
        }
        if (k == 5) {
            x = 0;
            cout << mi + 1 << " " << mj + 1 << " " << max << endl;
        }
    }
    if (x) {
        cout << "not found" << endl;
    }
    return 0;
}

题解
依次寻找每一个行列中的最大和最小值。

H - Lab杯 OpenJ_Bailian - 2992

“Lab杯”乒乓球赛就要在PKU的实验室之间举行了。人工智能实验室的学生都是乒乓球的狂热分子,都强烈希望代表实验室去比赛。但是有余名额限制,他们之中只能由一个人被选作代表。

为了让选择的过程公平,他们决定打一次单循环赛,每一对学生之间都打一场五局三胜的比赛。赢得最多比赛的人就将代表实验室去比赛。现在Ava手里有一份表,表里面记录了每一场比赛的比分。她应该让谁去比赛?

#include<bits/stdc++.h>
using namespace std;
void solve(){
    long long n;
    long long t = 0;
    cin >> n;
    long long a[n];
    long long array[n][n];
    for(long long i = 0;i < n;i ++){
        for(long long j = 0;j < n;j ++){
            cin >> array[i][j];
            if(array[i][j] == 3)t ++;
        }
        a[i] = t; 
        t = 0;
    }
    long long max = *max_element(a,a + n);
    for(long long i = 0;i < n;i ++){
        if(a[i] == max){
            cout << i + 1 << "\n";
            break;
        }
    }
}
int main(){
    solve();
}

题解
为五局三胜制,所以要求的是,如果遇到已经胜利三局的就将他的获胜数加一,随后对比虽有的获胜数,得出获胜局数最多的人。

I - 菲波那契数列(2) OpenJ_Bailian - 2758

菲波那契数列是指这样的数列: 数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。 给出一个正整数a,要求菲波那契数列中第a个数对1000取模的结果是多少。

#include<bits/stdc++.h>
using namespace std;
void solve(){
    vector<int> ans(1e6 + 5);
    ans[1] = 1;
    ans[2] = 1;
    for(int i = 3;i <= 1e6 + 5;i ++){
        ans[i] = (ans[i - 1] + ans[i - 2]) % 1000;
    }
    int x;
    cin >> x;
    cout << ans[x] << "\n";
}
int main(){
    int x;
    cin >> x;
    while(x --){
        solve();
    }
    return 0;
}

题解
循环方式求解斐波那契数列,但要注意对1000取模。

J - 2进制转化为16进制 OpenJ_Bailian - 2798

输入一个2进制的数,要求输出该2进制数的16进制表示。
在16进制的表示中,A-F表示10-15

#include <bits/stdc++.h>
using namespace std;
int cul(char x){
    if(x >= 'A'){
        return  x - 'A' + 10;
    }else{
        return x - '0';
    }
}
char pf(long long x){
    if(x >= 10){
        return x - 10 + 'A';
    }else if(x == 0){
        return '0';
    }
    else{
        return x + '0';
    }
}
void solve(){
    string s;
    string ans;
    cin >> s ;
    long long res = 0;
    for(int i = 0;i < s.length();i ++){
        res = res * 2 + cul(s[i]);
    }
    while(res > 0){
        ans = pf(res % 16) + ans;
        res /= 16; 
    }
    if(ans.empty())cout << 0 << "\n";
    else cout << ans << "\n";
}
int main()
{
    int n;
    cin >> n;
    while(n --){
        solve();
    }
    return 0;
}

题解
进制换算的通用写法,只需要对solve函数中的某些参数进行修改就可以改变进制转换的原进制和目标进制。

K - 方程求解 OpenJ_Bailian - 4140

求下面方程的根:f(x) = x3- 5x2+ 10x - 80 = 0。

#include<bits/stdc++.h>
#define f(x) (x*x*x-5*x*x+10*x-80)
//求导判断根的大致范围
using namespace std;
void solve(){
    double R = 10.0,L = 0.0;
    double mid;
    while(R-L>1e-10)
    {
        mid=L+(R-L)/2;
        if(f(mid)<0)
            L=mid;
        else
            R=mid;

    }
    printf("%.9f\n",mid);
}
int main(){
    solve();
    return 0;
}

题解
通过数学的方式进行求解,首先对函数进行求导,判断出此方程的递增区间与递减区间,在方程的每个驻点进行符号判断,依据零点定理来确定方程可能存在解的区域,从而使用二分法来求出解。

L - 表达式求值 洛谷 - P1981

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。
输入格式
一行,为需要你计算的表达式,表达式中只包含数字、加法运算符 + 和乘法运算符 *,且没有括号
输入数据保证这一行只有 0123456789+这12种字符。
输出格式
一个整数,表示这个表达式的值。
注意:当答案长度多于 4 位时,请只输出最后 4 位,前导 0 不输出。

#include<bits/stdc++.h>
using namespace std;
long long a,b,ans;
char ch;
stack<long long> s;
void solve(){
    cin >> a;
    a %= 10000;
    s.push(a);
    while(ch != '\n'){
        ch = getchar();
        if(ch == '\n') break;
        cin >> b;
        if(ch == '*'){
            a = s.top();
            s.pop();
            s.push(a * b % 10000);
        }
        else s.push(b);
    }
    while(s.size()){
        ans=(ans + s.top()) % 10000;
        s.pop();
    }
    cout << ans % 10000 << "\n";
}
int main(){
    solve();
}

题解
数据结构课堂学过的基本表达式的计算方式,此题对比书上的要求还更为容易判断,因为只存在+与×两种运算符号。 对表达式从前到后依次分析,是数字则入栈,是×号则取出输入数据与栈顶元素进行乘法,随后弹回栈中,当表达式内没有元素后则进行遍历,依次将剩余的数值进行加法操作,最后得数。

M - 四则运算表达式求值 OpenJ_Bailian - 4132

求一个可以带括号的小学算术四则运算表达式的值

#include<bits/stdc++.h>
using namespace std;
double factor_value();//读入一个因子,并且返回其值。
double term_value();//读入一个项,并返回其值。
double expression_value();//读入一个表达式,并返回其值。
int main()
{
    cout << fixed <<setprecision(2) << expression_value() << endl;
return 0;
}
double expression_value()
{
	double result = term_value();//求第一项的值
	while(true)//判断是否有多个项
	{
		char op = cin.peek();//看一个字符,不取走
		if(op == '+' || op == '-')//如果输入流中后续的字符是+或者-,则代表还有后续的项要处理。
		{
			cin.get();//从输入中取走一个值
			double value = term_value();
			if(op == '+')
			{
				result += value;
			}
			else
			{
				result -= value;
			}
			
		}
		else
		{
			break;
		}
	}
	return result;
}
double factor_value()
{
	double factor_result= 0;//此处变量不初始化,会造成bug 
	if(cin.peek() == '(')//取出的是左括号的情况,代表此处为一个表达式,
	{
		cin.get();
		factor_result = expression_value();
		cin.get();
	}
	else
	{
		while(isdigit(cin.peek()))//如果读到一个数字字符,对其进行处理
		{
				factor_result = 10 * factor_result + cin.peek() - '0';//必须初始化,第一次读数十位是0 
				cin.get();
		}
		if(cin.peek()=='.')//小数点处理
		{
			cin.get();
			double base_result=0;
			if(isdigit(cin.peek()))
			{
				for(double times =0.1; isdigit(cin.peek()); times *= 0.1)
				{
					base_result =  base_result + times*(cin.peek() - '0');//必须初始化,第一次读书十位是0 
					cin.get();
				}	
			}
		
			factor_result += base_result;
		}
		
	}
	return factor_result;
} 
double term_value()
{
	double term_result = factor_value();
	while(true)
	{
		char op = cin.peek();
		if(op == '*' || op == '/')
		{
			cin.get();
			double value = factor_value();
			if(op == '*')
			{
				term_result *= value;
			}
			else
			{
				term_result /= value;
			}
		}
		else
		{
			break;//more = false;//false not 1
		}
	}
	return term_result;
}

参考的是中国大学慕课郭炜老师课程讲解递归二
题解
表达式是一个递归的定义:
表达式中包含有项,项之间可以进行+或-操作,项中包含有因子,因子之间可以通过×或÷操作,因子中又含有表达式和整数,因此对于表达式可以进行递归分析处理。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

N - 八皇后 Checker Challenge 洛谷 - P1219

一个如下的
6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
在这里插入图片描述
上面的布局可以用序列 2 4 6 1 3 5 来描述,第 i 个数字表示在第 i 行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前3个解。最后一行是解的总个数。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n,ans = 0;
vector<int> a(maxn);
int col[maxn],row[maxn],line[maxn],rline[maxn];
void DFS(int k){
    if(k == n + 1){
        if(ans < 3){//输出前三种方案
             for(int i = 1;i <= n;i ++){
                cout << a[i] << " ";
            }
            cout << "\n";
        }
        ans ++;//总方案数
        return ;
    }
    for(int j = 1;j <= n;j ++){
    	//判断第k行第j个位置能不能放
        if(col[j] == 0 && row[j] == 0 && line[j + k] == 0 && rline[k - j + n] == 0){
            a[k] = j;//放入第k行第j列
            col[j] = row[j] = 1;//标记行和列
            line[j + k] = rline[k - j + n] = 1;//标记对角线
            DFS(k + 1);
            //回溯的时候取消标记
            col[j] = row[j] = 0;
            line[j + k]=rline[k - j + n] = 0;

        }
    }
}
int main()
{
    cin >> n;
    DFS(1);
    cout << ans;
    return 0;
}

题解
使用标记数组来对每一位及其对应的行列斜向进行,DFS来对每一个空位进行一次检索,并对其横竖斜向进行标记,如果后续棋子可以填入,则进行记录,如果不能填入则回溯,并对下一个空位进行判断,知道整个棋盘遍历完毕。

O - 开灯 洛谷 - P1876

首先所有的灯都是关的(注意是关!),编号为 1 的人走过来,把是 1 的倍数的灯全部打开,编号为 2 的人把是 2 的倍数的灯全部关上,编号为 3 的人又把是 3 的倍数的灯开的关上,关的开起来……直到第 N 个人为止。给定 N,求 N 轮之后,还有哪几盏是开着的。

#include<bits/stdc++.h>
using namespace std;
int main(){
    long long n;
    cin >> n;
    for(int i=1;i*i<=n;i++){
        cout << i * i << " ";
    }
    return 0;
}

题解
找规律题,只有按奇数次的时候灯才会亮着。一个数有几个因数就会被几下。因数都是成对出现的,平方数有奇数个因数。

P - 区间合并 计蒜客 - T1210

蒜头君给定n 个闭区间 [ai ,bi],其中 i=1,2,…,n。任意两个相邻或相交的闭区间可以合并为一个闭区间。例如,[1,2] 和 [2,3] 可以合并为 [1,3],[1,3] 和 [2,4] 可以合并为 [1,4],但是 [1,2] 和 [3,4] 不可以合并。我们的任务是判断这些区间是否可以最终合并为一个闭区间,如果可以,将这个闭区间输出,否则输出 “no”。

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n;
    cin >> n;
    vector<pair<int,int>> div(n + 1);
    for(int i = 1;i <= n;i ++){
        cin >> div[i].first >> div[i].second;
    }
    sort(div.begin() + 1,div.begin() + 1 + n);
    int r = div[1].first;
    for(int i = 1;i <= n;i ++){
        pair<int,int> c = div[i];
        if(r < c.first)
        {
            cout << "no";
            return ;
        }
        r = max(c.second,r);
    }
    cout << div[1].first << " " << r <<"\n";
}
int main(){
    solve();
    return 0;
}

题解
先对数组进行排序,遍历所有区间然后判断是否满足合并区间条件。

Q - 约瑟夫问题 洛谷 - P1996

n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

#include<bits/stdc++.h>
using namespace std;
void solve(){
    int n,m,s=0;
    cin >> n >> m;
    int visited[101] = {0};
    for(int k = 0;k < n;k ++){
        for(int i = 0;i < m;i ++){
            if(++ s > n)
                s = 1;
            if(visited[s])
                i --;
        }//类似取模,而因为序列是从1开始的,所以不取模,加判断;若visit过,则i--,使其继续循环
        cout << s << " ";
        visited[s]=true;//输出,记录已出队
    }
}
int main()
{
    solve();
    return 0;
}

题解
使用模拟,模拟到的数字出列。

R - 队列安排 洛谷 - P1160

一个学校里老师要将班上 N 个同学排成一列,同学被编号为 1∼N,他采取如下的方法:先将 1 号同学安排进队列,这时队列中只有他一个人;2∼N 号同学依次入列,编号为 i 的同学入列方式为:老师指定编号为 i 的同学站在编号为1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;从队列中去掉 M 个同学,其他同学位置顺序不变。在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。

#include<bits/stdc++.h>
using namespace std;
struct node{
    int pre, next;
}a[100000];
int n, m;
void addRight(int x, int pos) {//向某位置的右边进行插入
    a[x].pre = pos;
    a[a[pos].next].pre = x;
    a[x].next = a[pos].next;
    a[pos].next = x;
}
void addLeft(int x, int pos) {//向某位置的左边进行插入
    a[x].next = pos;
    a[a[pos].pre].next = x;
    a[x].pre = a[pos].pre;
    a[pos].pre = x;
}
void del(int x) {//对某位置执行删除操作
    if(a[x].pre == -1) return;
    a[a[x].pre].next = a[x].next;
    a[a[x].next].pre = a[x].pre;
    a[x].pre = -1;
    a[x].next = -1; 
}
void find() {
    int x = a[0].next;
    while(1) {
        cout<< x << " ";
        if(a[x].next == -1) break;
        x = a[x].next;
    }
}
void init() {//初始化链表
    for(int i = 1; i <= n; ++i) a[i].pre = a[i].next = -1;
    a[1].next = -1; a[1].pre = 0; a[0].next = 1;
}
int main() {
    cin >> n;
    int c1, c2;
    init();
    for(int i = 2; i <= n; ++i) {
        cin >> c1 >> c2;
        if(!c2) addLeft(i, c1);
        else addRight(i, c1);
    }
    cin >> m;
    for(int i = 1; i <= m; ++i) {
        cin >> c1;
        del(c1);
    }
    find();
    return 0;
}

题解
使用的数据结构为链表形式,对于分别写出左插入,右插入,删除的操作函数,对链表进行操作。

S - 机器翻译 洛谷 - P1540

小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果内存中有,软件就会用它进行翻译;如果内存中没有,软件就会在外存中的词典内查找,查出单词的中文含义然后翻译,并将这个单词和译义放入内存,以备后续的查找和翻译。假设内存中有 M 个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过 M−1,软件会将新单词存入一个未使用的内存单元;若内存中已存入 M 个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。假设一篇英语文章的长度为 N 个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。

#include<bits/stdc++.h>
using namespace std;
queue<int> q1;
int m,n;
int res;
bool mem[1010];
int main(){
    cin >> m >> n;
    for(int i = 1;i <= n;i ++){
        int x;
        cin >> x;
        if(mem[x])continue;
        else{
            if(q1.size() >= m){
                mem[q1.front()] = false;
                q1.pop();
            }
            q1.push(x);
            mem[x] = true;
            res ++;
        }
    }
    cout << res;
}

题解
有点类似OS中的先进先出页面置换算法,只需要开辟一个队列,然后用队列来进行操作,如待查找单词不存在内存中,则在外存中寻找,若此时队列不满,则直接插入队尾,若此时队列已满,则弹出队首元素,并将此单词插入队中。

T - 三连击 洛谷 - P1008

将 1,2,…,9 共 9 个数分成 3 组,分别组成 3 个三位数,且使这 3 个三位数构成 1:2:3 的比例,试求出所有满足条件的 3 个三位数。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a,b,c;
    for(a = 123;a <= 333;a ++)
            {
                b = a * 2;
                c = a * 3;
                if((a / 100 + a / 10 % 10 + a % 10 + b / 100 + b / 10 % 10 + b % 10 + c / 100 + c / 10 % 10 + c % 10 == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9) && ((a / 100) * (a / 10 % 10) * (a % 10) * (b / 100) * (b / 10 % 10) * (b % 10) * (c / 100) * (c / 10 % 10) * (c % 10) == (1) * (2) * (3) * (4) * (5) * (6) * (7) * (8) * (9)))
                    cout << a << " " << b << " "<< c << "\n";
            }
    return 0;
}

题解
可以组合成的最小的三位数就是123.333 * 3 = 999,为最大的三位数,所以只需要对123 - 333中的所有数进行模拟判断,如果符合题目要求则输出,不符合题目要求则继续判断。

U - 阶乘之和 洛谷 - P1009

用高精度计算出 S=1!+2!+3!+⋯+n!(n≤50)。
其中 ! 表示阶乘,定义为 n!=n×(n−1)×(n−2)×⋯×1。例如,5!=5×4×3×2×1=120。

#include<bits/stdc++.h>
using namespace std;
int a[120];
int b[120];//得数字符串
void add(int *a,int *b){
    int jw = 0;
    for(int i = 1;i <= 120 ;i ++){
        b[i] = b[i] + a[i] + jw;
        jw = b[i] / 10;
        b[i] = b[i] % 10;
    }
}
void mul(int *a,int c){
    int jw = 0;
    for(int i = 1;i <= 120;i ++){
        a[i] = a[i] * c + jw;
        jw = a[i] / 10;
        a[i] = a[i] % 10;
    }
}
int main(){
    int n;
    cin >> n;
    a[1] = 1;
    bool flag = 0;
    for(int i = 1;i <= n;i ++){
        mul(a,i);
        add(a,b);
    }
    for(int i = 120;i >= 1;i --){
        if(b[i] != 0) flag = 1;
        if(flag) cout << b[i];
    }
}

题解
很好的训练高精度计算的题,阶乘连续计算时,既要考虑高精度加法,也要考虑高精度乘法。高精度加法是将两个数组从低到高按位相加,如果超过了9就要进行进位操作,本题中的乘法由于是阶乘的形式,只需要将阶乘不断的乘上数值上大一的数字即可。

V - 幂次方 洛谷 - P1010

任何一个正整数都可以用 2 的幂次方表示。

约定次方用括号来表示,即 a^bab 可表示为 a(b)a(b)。

由此可知,137137 可表示为 2(7)+2(3)+2(0)2(7)+2(3)+2(0)

进一步:

7= 22+2+207=22+2+20 ( 2^121 用 22 表示),并且 3=2+2^03=2+20。

所以最后 137137 可表示为 2(2(2)+2+2(0))+2(2+2(0))+2(0)2(2(2)+2+2(0))+2(2+2(0))+2(0)。

又如 1315=2^{10} +2^8 +2^5 +2+11315=210+28+25+2+1

所以 13151315 最后可表示为 2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)。
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int a;
void fff(int x)
{
    for(int i = 14;i >= 0;i --)
    {
        if(pow(2,i) <= x){
            if(i == 1) cout << "2";
            else if(i == 0) cout << "2(0)"; 
            else{
                cout << "2(";
            fff(i);
            cout << ")";
            }
            x -= pow(2,i);
            if(x != 0) cout << "+";
        }
    }
}
int main()
{
    cin >> a;
    fff(a);
    return 0;
}

题解
用递归的方式对表达式进行求解。
参考如下题解:参考题解代码

W - 车站 洛谷 - P1011

火车从始发站(称为第 1 站)开出,在始发站上车的人数为 a,然后到达第 2 站,在第
2 站有人上、下车,但上、下车的人数相同,因此在第 2 站开出时(即在到达第 3 站之前)车上的人数保持为 a 人。从第 3 站起(包括第 3 站)上、下车的人数有一定规律:上车的人数都是前两站上车人数之和,而下车人数等于上一站上车人数,一直到终点站的前一站(第 n−1 站),都满足此规律。现给出的条件是:共有 n 个车站,始发站上车的人数为 a,最后一站下车的人数是 m(全部下车)。试问 x 站开出时车上的人数是多少?

#include <bits/stdc++.h>
using namespace std;
int a,n,m,x,ans;
int f[20],sum[20];
int main()
{
	cin >> a >> n >> m >> x;
	ans = a;
	if(x >= 3)
		ans += a;//特判
	if(x >= 4)
	{
		f[1] = f[2] = 1;	
		for(int i = 3;i <= n - 4;i ++)
			f[i] = f[i - 1] + f[i - 2];//求斐波那契数列
		for(int i = 1;i <= n - 4;i ++)
			sum[i] = sum[i - 1] + f[i];//求前缀和
		int y = (m - sum[n - 5] * a - ans) / sum[n - 4];//用推出的公式求y
		ans += sum[x - 4] * a + sum[x - 3] * y; //将答案加回
	}
	cout << ans << "\n";
	return 0;
}

题解
根据题意是一个斐波那契数列的问题:
对于每一个站,火车共有三个参数,分别是上车的人数, 下车的人数,和车上现有的人数,根据题目给的递推信息,发现关键的地方在于第二站上车和下车的人数是未知的,这时可以设未知量。
定义第一站上车为a,第二站上下车人数为b:
站数 1 2 3 4 5 6 ……
上车 a b a+b a+2b 2a+3b 3a+5b ……
下车 0 b b a+b a+2b 2a+3b ……
车内 a a 2a 2a+b 3a+2b 4a+4b ……
可见对于每一个车站的所有参数都是有公式的,将样例代入
4 * 5 + 4 * b = 32 b = 3 当 x = 4 代入得 人数为2 * 5 + 3 * 1 = 13
将表格修改为:
站数 1 2 3 4 5 6 ……
上车 1a+0b 0a+1b 1a+1b a+2b 2a+3b 3a+5b ……
下车 0a+0b 0a+1b 0a+1b a+b a+2b 2a+3b ……
车上 1a+0b 1a+0b 2a+0b 2a+b 3a+2b 4a+4b ……
用两个数组来分别表示参数
通过观察,发现从第4站开始,车上总人数与前两站总人数存在一定的关系,a的系数少1。
m = a * sum1[i - 1] + b * sum2[i - 1]
b = (m - a x sum1[i - 1]) / sum2[i - 1]
cout -> a * sum1[x] + b *sum2[x]
参考:车站

X - 拼数 洛谷 - P1012

设有 n 个正整数a1…an ,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数。

#include<bits/stdc++.h>
using namespace std;
bool cmp(const string& a, const string& b) {
    return a + b > b + a;
}
int main(){
    int n;
    cin >> n;
    vector<string> a(n);
    for (int i = 0; i < n; ++i)
        cin >> a[i];
    sort(a.begin(), a.end(), cmp);
    for (const string& str : a){
        cout << str;
    }
}

题解
直接对其按照首字母字典序排序,但是类似10与1这类排序会出现错误。所以a>b的排序规则需要改进,改进为a+b>b+a即可。

  • 30
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值