首页 > 试题广场 >

小美的代金券要过期啦

[编程题]小美的代金券要过期啦
  • 热度指数:2871 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

外卖节即将过去了,小美还有很代金券没有消费掉,美团面向小美这样的用户推出了一个新的活动,即代金券消消乐活动。系统会把小美的代金券打乱顺序排成一排,小美可以进行任意多次如下操作:

       如果存在相邻的两个代金券金额相等,设其面额为x,小美可以使用这两张代金券换一张面额为x+1的代金券,并将其仍放在原来两张券的位置上,每进行一次这样的操作,小美就可以获得1元可以无限期使用的奖励金。

       小美觉得奖励金可太香了,因此她想获得尽可能多的奖励金,请问她最多可以获得多少奖励金。


输入描述:

输入第一行仅包含一个正整数n,表示小美拥有的代金券数量。(1<=n<=500)

输入第二行包含n个正整数,每个整数x表示一张代金券的面额,同时这也是系统排出的代金券顺序。(1<=x<=100)



输出描述:
输出仅包含一个整数,表示小美最多可以获得的奖励金数量。
示例1

输入

5
1 1 1 1 1

输出

3

说明

{1,1,1,1,1}->{1,1,1,2}->{1,2,2}->{1,3}

#include<stdio.h>
int * fun(int num,int quan[]) {//排序
    int i, j;
    for (i = 0; i < num; i++)
        for (j = num - 1; j > 0; j--)
        {
            if (quan[num - 1] < quan[num - 2]) {
                int temp = quan[num - 1];
                quan[num - 1] = quan[num - 2];
                quan[num - 2] = temp;
            }
        }
    return quan;
}
int fun2(int num,int quan[]) {
    int i, j;
    int count = 0;
    int jishu;
    do {
        jishu = 0;
        for (i = 0; i < num - 1; i++)
            if (quan[i] == quan[i + 1] && quan[i] != 0) {
                jishu++;
                quan[i]++;
                i++;
                quan = fun(num, quan);
            }
        count += jishu;
    } while (jishu != 0);
    return count;
}
int main() {
    int num;
    int *r;
    scanf("%d", &num);
    int quan[num];
    for (int m = 0; m < num; m++)
        scanf("%d", &quan[m]);
    r = fun(num, quan);
    printf("%d", fun2(num,r));
}
只跑出来9个例子,但是不知道哪里错误了,希望有人能给我解答一下
编辑于 2021-08-13 17:42:00 回复(0)
第4题数据太水了吧,贪心明显不对啊,但是居然过了。。。
#include <bits/stdc++.h>

using namespace std;

int n, x;

int main() {
    ios::sync_with_stdio(false);
    cin >> n;
    stack<int> s;
    int ans = 0;
    while (n--) {
        cin >> x;
        while (!s.empty() && s.top() == x) {
            s.pop();
            ans++;
            x++;
        }
        s.push(x);
    }
    cout << ans;
    return 0;
}


发表于 2022-03-23 19:57:29 回复(0)
这道题实际上贪心搞不定,就是测试数据给的太弱了,任何一种贪心算法总能给出一个数据使得贪心遍历卡住出现诸如2123这样的能消的消不掉的情况。这道题多项式时间内应该是无解的
发表于 2021-10-02 19:37:35 回复(0)
由于并不关心最终剩下的代金券价值,所以只需要贪心地进行消消乐就可以了,使用双栈来求解。构建stackLeft和stackRight两个栈,其中左栈已经按顺序压入了所有代金券的金额。
(1)  如果左栈还有元素,就向右栈弹入一个元素(右栈为空,直接压入,否则进行(2)的判断)。
(2) 如果左右两个栈还有元素,且栈顶相等均为x,那两个栈就都进行一次弹栈操作,弹出的栈顶x自增1,表示两张价值为x的代金券换得了一张价值为x+1的代金券,奖励金+1;如果栈顶不相等,左栈弹栈直接将弹出的元素压入右栈。
(3) 对于(2)中新的代金券额度x,如果此时右栈没有元素了,就直接压入新的x;如果还有元素,就比较新的x与右栈栈顶的元素值,如果相等,右栈就弹出元素,x和奖励金都自增1,直到右栈没有元素或新的x与右栈栈顶不相等,然后向右栈压入新的x。
(4) 回到 (1) 继续,直到左栈为空,表示消消乐已经完成了。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Stack;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine().trim());
        String[] strArr = br.readLine().trim().split(" ");
        Stack<Integer> stackLeft = new Stack<>();
        Stack<Integer> stackRight = new Stack<>();
        for(int i = 0; i < n; i++)
            stackLeft.push(Integer.parseInt(strArr[i]));
        stackRight.push(stackLeft.pop());
        int money = 0;
        while(!stackLeft.isEmpty()){
            while(stackLeft.peek() == stackRight.peek()){
                int x = stackLeft.pop() + 1;    // 得到新的代金券值
                stackRight.pop();
                money ++;
                if(!stackRight.isEmpty()){
                    while(!stackRight.isEmpty() && stackRight.peek() == x){
                        x = stackRight.pop();
                        x ++;
                        money ++;
                    }
                    stackRight.push(x);
                }else
                    stackRight.push(x);
            }
            stackRight.push(stackLeft.pop());
        }
        System.out.println(money);
    }
}


编辑于 2021-02-28 12:21:56 回复(12)
这是原题啊。。
codeforces 1312e 难度2100 笔试还能考这种难度的
正解区间dp 去网上搜cf1312e就行
#include<bits/stdc++.h>

namespace MY_DEFINE {
#define ll long long
#define ull unsigned long long
#define db double
#define rep(x, a, b) for(int (x)=(a);(x)<=(b);(x)++)
#define per(x, a, b) for(int (x)=(a);(x)>=(b);(x)--)
#define reP(x, a, b) for(int (x)=(a);(x)<(b);(x)++)
#define Per(x, a, b) for(int (x)=(a);(x)>(b);(x)--)
#define scf(a) scanf("%d",&(a))
#define scfll(a) scanf("%lld",&(a))
#define ptf(a) printf("%d",a)
#define ptfll(a) printf("%lld",a)
#define ptfsp(a) printf("%d ",a)
#define ptfllsp(a) printf("%lld ",a)
#define pli(a, b) make_pair(a,b)
#define pb push_back
#define pYES puts("YES")
#define pNO puts("NO")
#define pYes puts("Yes")
#define pNo puts("No")
#define pYN(flag) puts((flag)?"YES":"NO")
#define pyn(flag) puts((flag)?"Yes":"No")
#define el puts("")
#define FS first
#define SE second
#define FAST_CIN_COUT ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    [[maybe_unused]] std::mt19937 rnd(time(nullptr));
}
using namespace std;
using namespace MY_DEFINE;
const int maxn = 5e2 + 5;
const int mod = 1e9 + 7;
namespace MOD_CALC {
    inline int sub(int a, int b, int M = mod) {
        a -= b;
        if (a < 0) a += M;
        return a;
    }

    inline int Plus(int a, int b, int M = mod) {
        a += b;
        if (a >= M) a -= M;
        return a;
    }

    inline int mul(int a, int b, int M = mod) {
        return (int) (1ll * a * b % M);
    }

    inline int qpow(int a, int n, int M = mod) {
        int ans = 1, b = a;
        while (n) {
            if (n & 1) ans = mul(ans, b, M);
            b = mul(b, b, M);
            n >>= 1;
        }
        return ans;
    }

    inline int Div(int a, int b, int M = mod) {
        return (int) (1ll * a * qpow(b, M - 2) % M);
    }

}
using namespace MOD_CALC;

int a[maxn], f[maxn][maxn], c[maxn][maxn], g[maxn];

signed main() {

    int n;
    scf(n);
    rep(i, 1, n) {
        scf(a[i]);
        f[i][i] = a[i];
    }
    rep(len, 2, n) {
        rep(i, 1, n) {
            int j = i + len - 1;
            rep(k, i, j - 1) {
                if (f[i][k] && f[k+1][j] && f[i][k] == f[k + 1][j] && c[i][k] + c[k + 1][j] + 1 >= c[i][j]) {
                    f[i][j] = f[i][k] + 1;
                    c[i][j] = c[i][k] + c[k + 1][j] + 1;
                }
            }
        }
    }
    rep(i, 2, n) {
        rep(j, 0, i - 1) {
            if (f[j + 1][i]) {
                g[i] = max(g[i], g[j] + c[j + 1][i]);
            }
        }
    }
    cout << g[n];

}


发表于 2022-02-08 18:16:46 回复(1)
采用链表方式
public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        Node head=new Node(-1);
        Node tem=head;  //临时,不用head直接
        while(sc.hasNext()){
            tem.next=new Node(sc.nextInt());
            tem=tem.next;
        }
        Node cur=head.next;
        int res=0;
        boolean flag=true;
        while(true){   //多次遍历,有可能前一位的和当前的相等了
            cur=head.next;  //重置
            flag=true;
            while(cur.next!=null){  //一次遍历
                if(cur.value==cur.next.value){
                    cur.value++;
                    cur.next=cur.next.next;
                    res++;
                    flag=false;
                }else{
                 cur=cur.next;   
                }            
            }
            if(flag==true) break;  //没有兑换的一趟可退出了
        }
        System.out.println(res);
    }
    static class Node{
        Node next;
        int value;
        Node(int value){
            this.value=value;
        }
    }


发表于 2021-10-05 20:47:32 回复(2)
想了半天觉得自己怎么也写不出这题,随便一写准备过部分case,就AC了,测试样例确实是相当的不全
发表于 2021-03-15 12:32:20 回复(2)
这样竟然也行




发表于 2022-03-24 10:14:33 回复(1)
使用单栈模拟消费券合成的过程

while True:
    try:
        num = int(input())
        elements = list(map(int,input().split()))
        stack = []
        ans = 0
        for ele in elements:
            if len(stack)==0:
                stack.append(ele)
            else:
                while ele == stack[-1]:
                    ans += 1
                    stack.pop()
                    ele += 1
                    if len(stack)==0:
                        break
                stack.append(ele)
        print(ans)
                    
    except:
        break

发表于 2022-08-12 23:07:44 回复(1)
n=int(input())
an=list(map(int, input().strip().split()))
stack=[]
res=0
for num in an:
    if not stack&nbs***bsp;stack[-1]!=num:
        stack.append(num)
    else:
        while stack and num==stack[-1]:
            stack.pop()
            num+=1
            res+=1
            
        stack.append(num)

print(res)


利用栈,每一个数x和栈顶元素相同则弹出,将x=x+1继续与栈顶元素比较,直到不等时入栈。
每弹出一次结果加一。

发表于 2022-03-25 17:35:11 回复(1)
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner =new Scanner(System.in);
        int n =scanner.nextInt();
        int[] nums =new  int[n];
        for (int i = 0; i < n; i++) {
            nums[i] =scanner.nextInt();
        }
        int res=0;


        for (int j = 1; j < n; j++) {
            if(nums[j-1]==nums[j]){
                res++;
                nums[j]=nums[j-1]+1;
                nums[j-1]=-1;
                for (int k = j-1; k >=0 ; k--) {
                    if(nums[k]!=-1){
                        if(nums[j]==nums[k]){
                            res++;
                            nums[j]=nums[j]+1;
                            nums[k]=-1;
                        }else {
                            break;
                        }
                    }
                }


            }


        }
        System.out.println(res);
    }
}
没有用动态规划,但是也都成功了。有没有人觉得代码有逻辑错误?
发表于 2023-08-24 21:11:42 回复(0)
#include <iostream>
#include <vector>
using namespace std;
int n,b,ans=0;

void uni(int l,int r,vector<int>& nums){
    if(l>=r) return;
    for(int i=l;i<r;++i){
        if(nums[i]==nums[i+1]){
            // cout<<nums[i]<<" "<<nums[i+1]<<endl;
            ans++;
            nums[i]+=1;
            nums[i+1]+=1;
            if(i-1>0&&nums[i-1]==nums[i]) uni(l,i,nums);
            if(i+2<r&&nums[i+2]==nums[i+1]) uni(i+1,r,nums);
        }
    }
}
int main() {
    vector<int> nums;
    cin>>n;
    for(int i=0;i<n;++i){
        cin>>b;
        nums.push_back(b);
    }
    uni(0,n-1,nums);
    cout<<ans<<endl;
    return 0;
}
// 64 位输出请用 printf("%lld")
过了70%不知道错在哪求指点
发表于 2023-08-11 17:19:16 回复(0)

为什么这样也能过啊- -?
发表于 2023-08-08 23:34:49 回复(0)
暴力求所有最后能合成一够合成一个数的所有区间,最后dp求从这些区间中最少使用几个能覆盖
满1-n整个区间,求出来的结果就是剩下的代金券数,用n减去代金券数就是答案
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define f(i,c,d) for(int i=c;i<d;i++)
#define debug(a) cout << #a:  << a << endl;
#define ios ios::sync_with_stdio(false);cin.tie(0);
#define INF 0x3f3f3f3f
#define pii pair<int,int> 
#define ll long long
inline int read() {
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f;
}
const int N = 2e5+5;
vector<pair<int,int> > b[1500],all;
void push(int x,int y,int v){
	//x左区间,y右区间,v区间值
	for(auto it: b[v]){
		if(it.first == y+1){
			push(x,it.second,v+1);
		}
		if(x == it.second +1){
			push(it.first,y,v+1);
		}
	}
	b[v].push_back({x,y});
	all.push_back({x,y});
}
int main(){
	int n;
	cin>>n;
	vector<int> a(n+5);
	for(int i=1;i<=n;i++) cin>>a[i];
	
	for(int i=1;i<=n;i++){
		//递归暴力求所有最后能合成一个数的区间
		push(i,i,a[i]);
	}
	//线性dp求最小能覆盖1-n的区间数
	int dp[505];
	memset(dp,INF,sizeof dp);
	dp[0]=0;
	sort(all.begin(),all.end());
	for(auto it: all){
		int x = it.first;
		int y = it.second;
		dp[y] = min(dp[y],dp[x-1]+1);
	}
	cout<<dp[n]<<endl;
	return 0;
}



发表于 2023-08-08 16:58:46 回复(0)
#include <iostream>
#include <vector>
#include <map>
using namespace std;
 
intmain() {
    intn;
    cin>>n;
    map<int,int> freMap;
    vector<int> arr(n,0);
    for(inti=0;i<n;i++){
        cin>>arr[i];
    }
    intans = 0;
    inti = 0;
    while(i<n-1){
        if(arr[i]==arr[i+1]){
            ans++;//先将上面等于+1,然后再向两边扩,选扩的最大值长度
            intl = i,r=i+1;
            arr[l]=arr[l]+1;
            arr[r]=arr[r]+1;
            while(r<n-1&& arr[r]==arr[r+1]){
                arr[r+1]=arr[r]+1;
                arr[r] = arr[r]+1;
                ++r;
            }
            while(l>0&& arr[l]==arr[l-1]){
                arr[l] = arr[l]+1;
                arr[l-1] = arr[l]+1;
                --l;
            }
            intlen1 = r-(i+1);
            intlen2 = i-l;
            if(len1>len2){
                ans+=len1;
            }else{
                ans+=len2;
            }
            i=r+1;
        }
        else
            i++;
    }
    cout<<ans<<endl;
    return0;
}
发表于 2023-06-16 11:00:05 回复(1)
#include <iostream>
using namespace std;
/*
    dp[i,j)          表示对 arr[i,j)进行合并可以产生的尽量多的奖励金。
 
    combine[i,j)     表示   arr[i,j)能否通过某种顺序合并为一个元素,如果可以该元素就是combine[i,j),否则combine[i,j)==0
 
    (如果arr[i,j)能合并为一个元素,则该元素一定是唯一的:可以这样来考虑这件事情,假设arr[i,j)最小的元素为k,则我们不关心
    具体是怎么合并的,但所有的k一定通过合并变为k+1,实际上,我们总可以先把所有的k消掉。接着,剩余的最小元素为k+1,... 如此下去,
    每一轮中,arr[i,j)中最小元素的个数都是确定的,arr[i,j)中本来的元素个数也是确定的,因此,最终可以合并成的那个元素也是确定的)
 
    那么    combine[i,j) == if exists  {i+1<=k<j}  s.t.  combine[i,k) == combine[k,j) != 0 
                                then  combine[i,k)+1
                                else  0
 
    dp[i,j) = if combine[i,j) != 0 then j-i-1                          (如果能全部合并,肯定是全部合并最划算,因为消掉的元素最多)
                                   else max{i+1<=k<j}(dp[i,k)+dp[k,j)
*/

int dp[503][503];
int combine[503][503];
// int nodes[503];

int main() {
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>combine[i][i+1];

    for(int len = 2;len<=n;len++){
        for(int i=1;i<=n+1-len;i++){
            int j = i+len;
            int k = 0;
            for(k=i+1;k<j;k++){
                if(combine[i][k]!=0&&combine[i][k]==combine[k][j])
                    break;
            }
            if(k<j)
                combine[i][j] = combine[i][k]+1;
            else
                combine[i][j] = 0;
        }   // combine

        for(int i=1;i<=n+1-len;i++){
            int j = i+len;
            if(combine[i][j]!=0){
                dp[i][j] = len-1;
                continue;
            }
            for(int k=i+1;k<j;k++){
                dp[i][j] = max(dp[i][j],dp[i][k]+dp[k][j]);
            }
        }
    }

    cout<<dp[1][n+1];
}
// 64 位输出请用 printf("%lld")

发表于 2023-05-04 18:07:49 回复(0)
贪心,但是经牛友提醒,是测试样例不全才AC的,有无大佬给出正确的做法
import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        LinkedList<Integer> num = new LinkedList<Integer>();
        int flag = 1;
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            num.add(in.nextInt());
        }
        while(flag != 0)
        {
            flag = 0;
            for(int i = 0; i < num.size() - 1; i++)
            {
                if(num.get(i) == num.get(i + 1))
                {
                    flag = 1;
                    ans++;
                    num.remove(i + 1);
                    num.set(i, num.get(i) + 1);
                    break;
                }
            }
            
        }
        System.out.println(ans);
        
    }
}


编辑于 2023-04-20 00:46:23 回复(0)
直接就在原数组上合,很暴力
n = int(input())
values = [int(x) for x in input().split()]
count = 0
i = 1
while i < len(values):
    if values[i] == values[i-1]:
        values.pop(i-1)
        values[i-1] = values[i-1] + 1
        count += 1
        i = 1
    else:
        i += 1
print(count)
然后发现53ms............

发表于 2023-04-14 02:07:27 回复(0)

双指针+数组(System.arraycopy)

直接判断nums[index] he nums[index+1]相不相等,不相等index++,相等将nums[index]++, 并将数组的右边的所有值左移(arraycopy不会太慢)然后将index回溯一个(不为0的时候),再继续匹配。
实际上本来应该用双向链表做的,这里是用数组模拟。
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n];
        for (int i=0; i<n; i++) {
            nums[i] = in.nextInt();
        }
        int index = 0;
        int end = n-1;
        int mergeTimes = 0;
        while(index < end) {
            if (nums[index] != nums[index+1]) {
                index++;
                continue;
            }
            nums[index] = nums[index] + 1;
            if (index < end -1) {
                System.arraycopy(nums, index+2, nums, index+1, end-(index+1));
                // end--;就可以了,将nums[end]设为零主要是调试好看
                nums[end--] = 0;
            }
            if (index > 0) {
                index--;
            }
            mergeTimes++;
        }
        System.out.println(mergeTimes);
    }
}


发表于 2022-09-20 19:47:55 回复(0)
链接:https://www.nowcoder.com/questionTerminal/a9980f73060545ca923344098750af18?toCommentId=14119234
来源:牛客网
可以去搜索: cf1312e 
考虑令d p [ i ] [ j ] dp[i][j]dp[i][j]为区间[ i , j ] [i, j][i,j]所能合并的最小长度,w [ i ] [ j ] w[i][j]w[i][j]为区间[ i , j ] [i,j][i,j]所能合并出来的和 
那么可以很简单的得出这样一个式子    dp [ i ] [ j ] = min ⁡ ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] ) 
                                                              dp[i][j] = \min(dp[i][j], dp[i][k]+dp[k+1][j]) 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.Scanner;
public class Main {
 
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] dp = new int[n + 1][n + 1];
        int[][] w = new int[n + 1][n + 1];
        for (int i = 1; i <= n; i++) {
            dp[i][i] = 1;
            w[i][i] = sc.nextInt();
        }
        // 初始化 dp[i][j] 的区间长度
        for (int i = 1; i <= n; i++) {
            for (int j = i; j <= n; j++) {
                dp[i][j] = j - i + 1;
            }
        }
       
        // len 表示遍历的长度,依次从这些长度中去更新区间最小长度
        for (int len = 1; len <= n; len++) {
            for (int i = 1; i + len <= n ; i++) {
                for (int j = i; j <= i + len -1; j++) {
                    dp[i][len + i] = Math.min(dp[i][len + i], dp[i][j] + dp[j + 1][i +len]);
                    if(dp[i][j] == 1 && dp[j + 1][i + len] == 1 && w[i][j] == w[j + 1][i + len]){
                        dp[i][i + len] = 1;
                        w[i][i + len] = w[i][j] + 1;
                    }
                }
            }
        }
 
//        System.out.println(dp[1][n]);
 
        System.out.println(n - dp[1][n]);
    }
 
 
}
发表于 2022-09-02 11:46:46 回复(0)