ali编程题

本篇博客探讨了多种算法和数据结构在解决实际问题中的应用,包括动态规划、贪心策略、深度优先搜索等。通过实例解析,展示了如何利用这些工具优化问题求解,提高效率。同时,博客还涵盖了排序算法、哈希表和图论在实际场景中的应用。
摘要由CSDN通过智能技术生成

第1题
输出描述:
一行一个数字表示答案

输入例子1:
5 3
2 11 21
19 10 1
20 11 1
6 15 24
18 27 36

输出例子1:
3

#include <iostream>
#include <vector>
#include <map>
using namespace std;

int main(){
    int n, k;
    cin >> n >> k;
    map<vector<int>, int> imap; // 列差取-,个数
    int res = 0;
    for(int i = 0; i < n; i++){
        vector<int> a(k); //存一行数字
        for(int &t : a) cin >> t;
        vector<int> b(k-1); //存列差
        for(int j = 1; j < k; j++)
            b[j-1] = a[j] - a[j-1];
        res += imap[b]; //b逐个元素取-值,然后加1,在此处累加
        for(int &t: b) t = -t;
        imap[b]++;
    }
    cout << res << endl;
}


-------------------------------------------------------------------

第2题

输入描述:
对于每一组测试数据, 每行输入个数和。

输出描述:
对于每组输入样例,按字典序输出所有方案选择物品的编号,每种方案占一行

输入例子1:
4 1

输出例子1:
1
2
3
4

输入例子2:
5 2

输出例子2:
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5

#include <iostream>
#include <vector>
using namespace std;
void select(vector<int>& nums, vector<int> comb, int begin, int k){
     if(k <= 0){
         if(k == 0){
             for(int i = 0; i < comb.size(); i++){
                 cout << comb[i] << " ";
             }
             cout << endl;
         }
     }
     for(int i = begin; i < nums.size(); i++){
         comb.push_back(nums[i]);
         select(nums, comb, i + 1, k -1);
         comb.pop_back();
     }
}

int main(){
    int n, m;
    cin >> n >> m;
    if(n < m) return 0;
    vector<int> comb;
    vector<int> nums(n, 0);
    for(int i = 0; i < n; i++)
        nums[i] = i + 1;
    select(nums, comb, 0, m);
    return 0;
}-------------------------------------------------------------------

第三题

题意:n个人过河,一次最多过两人,时间取决于最慢的,求全部渡过河的所用最小时间。

思路:

通过总结分析可得当n为1时,用时a[1],当n为2时,取决于二者最大时间,当n为3时,最小时间为三人用时总和。

当n大于等于4时有两种渡河方案:1、最快和次快先过,最快回,然后当前最慢和当前次慢的过,次快回。
time=a[2]+a[n]+a[1]+a[2].2、始终最快和当前最慢的过河,最快回。在取时间时,要从两者中选最小。
time=a[n]+a[1]+a[n-1]+a[1].

       ab                     ad
    ---------->           ----------> 
        a                      a
    <----------           <----------
        cd                    ac
    ---------->           ----------> 
        b                      a
    <----------           <----------
        ab                     ab
    ---------->           ---------->          
     a + 3b + d             2a + b + c + d
     

Sample Input

1
4
1 2 5 10
Sample Output

17

   
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


int cross_river(vector<int>& vec, int num)
{
    int sum = 0;

    if(num == 1) //如果只有一个人
        return vec[1];
    if(num == 2) // 如果只有两个人
        return vec[2];
    if(num == 3) //如果有三个人
        return vec[1] + vec[2] + vec[3];
    for(int j = 2; j <= num; j++)
        sum += vec[j];

    // 最快的送每一个过河  vec[1] * (num - 2) + sum
    // 最快和次快过,最快回, 最慢和次慢过,次快回,递归下去,剩下num-2人
    return min(sum + vec[1]*(num-2) , vec[1] + vec[2]*2 + vec[num] + cross_river(vec, num -2));
}

int main(){
    int tn, num;
    cin >> tn;
    while(tn--){
        int min = 0;
        cin >> num;
        vector<int> vec(num + 1);
        for(int i = 1 ; i <= num; i++){
            cin >> vec[i];
        }
        sort(vec.begin()+1, vec.begin()+1+num);
        min = cross_river(vec, num);
        cout << min << endl;
    }

    return 0;
}

 方法二:
迭代改为循环

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(){
    int tn, n;
    cin >> tn;
    while(tn--){ 
        int time = 0;
        cin >> n;
        vector<int> vec(n + 1); 
        for(int i = 1 ; i <= n; i++){
            cin >> vec[i];
        }
        sort(vec.begin()+1, vec.begin()+1+n);
        while(n > 0){
            if(n == 1){
                time += vec[1];
                break;
            }
            if(n == 2){
                time += vec[2];
                break;
            }
            if(n == 3){
                time += vec[1] + vec[2] + vec[3];
                break;
            }
            else{
                // 最快和次快过,最快回, 最慢和次慢过,次快回; 最快的送最慢和次慢过河
                time = time + min(vec[n] + 2*vec[2] + vec[1], vec[1] * 2 + vec[n] + vec[n-1]);
                n = n-2;
            }
        }
        cout << time << endl;
    }
    return 0;
}
-----------------------------------------------
第4题

小强想要从中选出一个整数,从中选出一个整数 .使得满足  = 的同时且和的乘积最大。如果不存在这样的和,请输出“ 0 0”.

输入描述:
输入一行包含四个整数,,和.


输出描述:
输出两个整数表示满足条件的和.若不存在,则输出"0 0".

输入例子1:
1 1 2 1

输出例子1:
0 0

输入例子2:
1000 500 4 2

输出例子2:
1000 500

输入例子3:
1000 500 3 1

输出例子3:
999 333

#include <iostream>

using namespace std;

int maxG(int a, int b){
    int c = 0;
    while(b != 0){
        c = a % b;
        a = b;
        b = c;
    }
    return a;
}

int main(){
    int A, B, a, b;
    long x, y;
    cin >> A >> B >> a >> b;
    //求a b最大公约数
    int mg = maxG(a, b);
    //约分
    a = a/mg;
    b = b/mg;
    //判断x,y是否存在
    if( A < a || B < b){
        x = 0;
        y = 0;
    }else{
        x = a;
        y = b;
        while(x + a <= A && y + b <= B){
            x += a;
            y += b;
        }
    }
    cout << x << " " << y << endl;
}
-----------------------------------------------------------------
第5题

在一张2D地图上小强有n座房子,因为地理位置的原因没有办法给每座房子提供水源,所以小强打算修建一条平行y轴的水渠.因为这条水渠无限长.
所以能够看做是一条平行于y轴的直线. 现在小强想确定修建水渠的位置,能够使得这座房子到水渠的垂直距离和最小,请你输出最小的距离和.

输入描述:
第一行输入一个正整数.
接下来行,每行输入两个正整数,,分别表示每个房子所在的二维坐标.

输出描述:
输出一个整数表示答案

输入例子1:
4
0 0
0 50
50 50
50 0

输出例子1:
100

例子说明1:
当修建水渠位置的直线方程为\mathit x=0或者\mathit x=50时,都能获得最小距离和. 
 
 
思路:只需取中位数的点便可以得到答案。
例如:
1,9两点,要得到到1,9两点距离之和最小的点,只需取[1,9]内任意一点便可得到最小值。
同理:
若是求到1,3,6,9这四个点距离之和最小的点,
先看[1,9]区间内任意一点到1,9的距离都是最短。
再看[3,6]区间内同样区间内任意一点到3,6的距离都是最小值。
故只需求这两个区间的交集[3,6]内取任意一点便可得到到这四点距离之和的最小值。
因此若n为奇数我们便取这n个点的中位数点。
若n为偶数我们便取这n个点的中间两个点的任意一个(排完序后所得交集区间的端点)
得出所得点l应为(n+1)/2.

注意ans应为long long类型。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main(){
    int n;
    long long sum = 0;
    cin >> n;
    vector<int> x(n + 1);
    vector<int> y(n + 1);
    for(int i = 1; i <=n ; i++){
        cin >> x[i];
        cin >> y[i];
    }
    sort(x.begin() + 1, x.begin() + 1 + n);
    int mid = (1 + n)/2;
    for(int j = 1; j <= n; j++){
        sum += abs(x[j] - x[mid]);
    }
    cout << sum << endl;
}

 -----------------------------------------------------------------
 第6题
国际交流会(圆桌问题)

最近小强主办了一场国际交流会,大家在会上以一个圆桌围坐在一起。由于大会的目的就是让不同国家的人感受一下不同的异域气息,
为了更好地达到这个目的,小强希望最大化邻座两人之间的差异程度和。为此,他找到了你,希望你能给他安排一下座位,
达到邻座之间的差异之和最大。

输入描述:
输入总共两行。
第一行一个正整数,代表参加国际交流会的人数(即圆桌上所坐的总人数,不单独对牛牛进行区分)
第二行包含个正整数,第个正整数a_i代表第个人的特征值。
其中
注意:
邻座的定义为: 第人的邻座为,第人的邻座是,第人的邻座是。
邻座的差异值计算方法为。
每对邻座差异值只计算一次。

输出描述:
输出总共两行。
第一行输出最大的差异值。
第二行输出用空格隔开的个数,为重新排列过的特征值。
(注意:不输出编号)
如果最大差异值情况下有多组解,输出任意一组即可。

输入例子1:
4
3 6 2 9

输出例子1:
20
6 2 9 3

例子说明1:
这么坐的话
差异和为\text |6-2|+|2-9|+|9-3|+|3-6|=20为最大的情况。
 
 
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(){
    int n;
    long long sum = 0;
    cin >> n;
    vector<int> diffnum(n);
    vector<int> res;
    for(int i = 0; i < n; i++){
        cin >> diffnum[i];
    }
    sort(diffnum.begin(),diffnum.end());
    for(int j = 0; j < n/2; j++){
        res.push_back(diffnum[j]);
        res.push_back(diffnum[n - j -1]);
    }
    if(n % 2 != 0)
        res.push_back(diffnum[n/2]);
    for(int k = 1; k < n; k++){
        sum += abs(res[k] - res[k-1]);
    }
    sum += abs(res[n-1] - res[0]);
    cout << sum << endl;
    for(int ii = 0; ii < n; ii++)
        cout << res[ii] << " ";
    cout << endl;
}

-------------------------------------------------------------------
第7题
[编程题]小强的神奇矩阵

小强有一个的矩阵,他将中每列的三个数字中取出一个按顺序组成一个长度为的数组,即b_i可以是其中任意一个。问的最小值是多少。
 sum |b(i) - b(i+1)| 最小值
输入描述:
第一行,一个正整数。
第二行到第四行输入一个的矩阵,每行输入个正整数。

输出描述:
一行一个正整数表示答案。

输入例子1:
5
5 9 5 4 4
4 7 4 10 3
2 10 9 2 3

输出例子1:
5

例子说明1:
数组\mathit b可以为\left[5,7,5,4,4\right],答案为\text 5。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(){
    int col;
    cin >> col;
    vector<vector<int> > input(3, vector<int> (col));
    vector<vector<long> > dp(3, vector<long>(col));
    long d0, d1, d2;
    long min_value;
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < col; j++)
        {
            cin >> input[i][j];
        }
    }
    for(int j = 1; j < col; j++)
    {
        for(int i = 0; i < 3; i++){
            d0 = abs(input[0][j-1] - input[i][j]) + dp[0][j-1];
            d1 = abs(input[1][j-1] - input[i][j]) + dp[1][j-1];
            d2 = abs(input[2][j-1] - input[i][j]) + dp[2][j-1];
            dp[i][j] = min(min(d0,d1),d2);
        }
    }
    min_value = min(min(dp[0][col-1],dp[1][col-1]),dp[2][col-1]);
    cout << min_value << endl;
}

-------------------------------------------------------------------
第8题
[编程题]蚂蚁森林之王
时间限制:C/C++ 2秒,其他语言4秒

空间限制:C/C++ 256M,其他语言512M

很久很久以前,在蚂蚁森林里住着  只小动物,编号从  到  。编号越小的动物能力值越大。现在他们想投票选出一只小动物当森林之王,
对于每只小动物来说,如果他有崇拜的对象,那么他可能投票选择自己,或与自己崇拜的对象投相同票;如果他没有崇拜的对象,那么他投票只可能选择自己。
每只小动物只会崇拜能力值比自己大的小动物。
记者小强拜访了这  只小动物,了解到每只小动物是否有崇拜的对象以及具体是谁。现在他想知道每个人能得到的最高票数是多少。

输入描述:
第一行一个正整数  ,代表小动物的数量。
第二行  个以空格分隔的正整数  ,代表每只小动物崇拜的小动物。 
若 ,则代表第  只小动物没有崇拜的对象。
 。
保证 。

输出描述:
共  行,第  行代表第  只小动物可能得到的最多票数。

输入例子1:
4
0 1 1 1

输出例子1:
4
1
1
1

例子说明1:
如果第 \text 2,3,4 只小动物均和第一只投一样的票,则第一只小动物可以获得四票。


#include <iostream>
#include <vector>
using namespace std;


int main(){
    int n;
    cin >> n;
    vector<int> input(n+1);
    vector<int> res(n+1, 0);
    for(int i = 1; i < n+1; i++){
        cin >> input[i];
    }
    for(int i = n; i > 0; i--){
        res[i] += 1;
        res[input[i]] = res[input[i]] + res[i];
    }
    for(int i = 1; i <= n; i++){
        cout << res[i] << endl;
    }
}
-------------------------------------------------------------
第九题
[编程题]删除字符
时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 256M,其他语言512M

有一个长度为的字符串 ,你可以删除其中的 个字符,使剩余字符串的字典序最小,输出这个剩余字符串。

输入描述:
第一行输入一个整数,代表接下来有组测试数据。
对于每一组测试数据,第一行输入两个数代表字符串的长度和可以删除的字符数量。
接下来输入长度为字符串。

输出描述:
对于每一组数据,输出一个答案

输入例子1:
2
5 2
abcab
10 4
lkqijxsnny

输出例子1:
aab
ijsnny

ijklnnqsxy


#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>
using namespace std;

void deleteM(string str, int m){
    stack<char> stk;
    for(int i = 0; i < str.length(); i++){
        char cur = str[i];
        while(!stk.empty() && stk.top() > cur && m > 0){
            stk.pop();
            m--;
        }
        stk.push(cur);
    }
    //m不为0, 不满足删除个数,继续删除
    for(int i = 0; i < m; i++)
        stk.pop();
    string res;
    while(!stk.empty()){
        res = stk.top() + res;
        stk.pop();
    }
    cout << res << endl;
}

int main()
{
    long len, m, n;
    cin >> n;
    while(n--){
        cin >> len >> m;
        string str;
        cin >> str;
        deleteM(str,m);
    }
}

-------------------------------------------------------------------
第10题

小强今天体检,其中有一个环节是测视力
小强看到的视力表是一张的表格,但是由于小强视力太差,他无法看清表格中的符号。
不过热爱数学的他给自己出了这样一个问题:假设现在有a个向上的符号,b个向下的符号,
c个向左的符号,d个向右的符号,把这些符号填到视力表中,总共有多少种可能的情况呢?
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long

ll qmi(ll a, ll k, ll p){
    int res = 1;
    while(k){
        if(k & 1) res = res*a % p;
        a = a*a%p;
        k>>=1;
    }
    return res;
}

ll C(ll a, ll b, ll p){
    if(b > a) return 0;
    ll res = 1;
    for(ll i = 1, j = a; i <= b; i++, j--){
        res = res*j %p;
        res = res*qmi(i, p -2, p)%p;
    }
    return res;
}

ll lucas(ll a, ll b, ll p){
    if(a < p && b < p) return C(a, b, p);
    return C(a%p, b%p, p) * lucas(a/p,b/p,p)%p;
}

signed main(){
    int n, a, b, c, d;
    cin >> n >> a >> b >> c >> d;
    int  p = 998244353;
    ll ans = lucas(n * n, n * n - a, p) * lucas(n * n - a, b, p) %p;
    ans *= lucas(n * n - a - b, c, p) %p;
    cout << ans % p << endl;
}
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值