牛客等级之题8.4——题解

购物

题目描述
在遥远的东方,有一家糖果专卖店。
这家糖果店将会在每天出售一些糖果,它每天都会生产出m个糖果,第i天的第j个糖果价格为C[i][j]元。
现在的你想要在接下来的n天去糖果店进行选购,你每天可以买多个糖果,也可以选择不买糖果,但是最多买m个。(因为最多只生产m个)买来糖果以后,你可以选择吃掉糖果或者留着之后再吃。糖果不会过期,你需要保证这n天中每天你都能吃到至少一个糖果。
这家店的老板看你经常去光顾这家店,感到非常生气。(因为他不能好好睡觉了)于是他会额外的要求你支付点钱。具体来说,你在某一天购买了 k 个糖果,那么你在这一天需要额外支付 k^2 的费用。
那么问题来了,你最少需要多少钱才能达成自己的目的呢?

输入描述:
第一行两个正整数n和m,分别表示天数以及糖果店每天生产的糖果数量。
接下来n行(第2行到第n+1行),每行m个正整数,第x+1行的第y个正整数表示第x天的第y个糖果的费用。
输出描述:
输出只有一个正整数,表示你需要支付的最小费用。
示例1
输入
3 2
1 1
100 100
10000 10000
输出
107
示例2
输入
5 5
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
输出
10
备注:
对于100%的数据,1 ≤ n, m ≤ 300 , 所有输入的数均 ≤ 10^6。

题解1:排序和优先队列。每天要加上k^2的额外费用,所以我们先处理一下这个,把每地方处理一下,就是每天价格排序,从小到大,每个糖果价格一次加上1,3,5…因为 k^2为首项1,差为2的等差数列前n项和。当把一天生产的糖果按序放入队列后,就要来选择队列中糖果的最小的花费(买的要么是之前的,要么是刚放入的这天的糖果),要保证每天都至少有一个糖果可以吃。因为每天的糖果要么是从当天的糖果中选择的,要么是之前的天生产的糖果中选的。

#include<bits/stdc++.h>
using namespace std;
int cost[305][305];
int main()
{
    
    
    priority_queue<int,vector<int>,greater<int> >q;//注意最后两个尖号之间的空格

    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&cost[i][j]);
    
    //对每一天的生产的m个糖果进行排序
    for(int i=1;i<=n;i++)
        sort(cost[i]+1,cost[i]+1+m);
        
    /*排序后将额外支付的k^2直接加到每个糖果上 
	因为已经排好序 所以每天的糖果将依次加上1,2,3...*/
	
    //将每一天的生产的按排序后的顺序放入优先队列
    for(int i=1; i<=n; i++)
    {
    
    
        int add = 1;
        for(int j=1;j<=m;j++)
        {
    
    
            cost[i][j]+=add;
            add+=2;
        }
    }
    int ans = 0;
    for(int i=1; i<=n; i++)
    {
    
    
        for(int j=1;j<=m;j++)
            q.push(cost[i][j]);
        
        ans += q.top();
        q.pop();
    }
    cout<<ans<<endl;
    return 0;
}

题解2:DP
以 dp[i][j] 表示前 i 天买 j 个糖果的最小代价,那么枚举第 i+1 天买的糖果数量即有转移方程:
在这里插入图片描述
其中 c[i][j] 表示在第 i 天买 j 个糖果所需的最小代价,dp[n][n] 即为答案,时间复杂度O(n^3)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 305
int n,m;
ll c[maxn][maxn],dp[maxn][maxn];

int main()
{
    
    
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
	{
    
    
		for(int j=1; j<=m; j++)
			scanf("%lld",&c[i][j]);
		sort(c[i]+1,c[i]+m+1);
		
		for(int j=2; j<=m; j++)
		    c[i][j]+=c[i][j-1];
	}
	
	for(int i=0;i<=n;i++)
		for(int j=1;j<=n;j++)	dp[i][j]=1e15;
		
	for(int i=0;i<n;i++)
		for(int j=0;j<=n;j++)
			if(j>=i&&dp[i][j]!=1e15)
				for(int k=max(0,i+1-j);k<=min(n-j,m);k++)
					dp[i+1][j+k]=min(dp[i+1][j+k],dp[i][j]+c[i+1][k]+k*k);
	printf("%lld\n",dp[n][n]);
	return 0;
}

拯救单身狗

题目描述
在双11期间,我们程基内部举行了一个秘密会议, 会议的主题是:拯救单身狗!为此我们程基举办了一个活动, 邀请学校内的同学来参加。在活动上,我们给每个参与者发了一件印有数字的T-shirt, 规定如果两者的数字, 则算配对成功。现在糖要知道是否存在奇数次的T-shirt(保证只出现一次),有的话他就要负责去采购衣服了。

输入描述:
第一个为测试样例的组数T,接下来为一串数字序列,每个数字代表有这样的编号的T-shirt一件,T-shirt的编号是在1~1000000中随机选取的, 每组数据以0作为结束标志。
输出描述:
对于一组数据,输出一行,若不缺衣服输出“Yes”,否则输出"No"。
示例1
输入
2
2 2 2 3 3 0
2 2 4 4 0
输出
No
Yes

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int mod=1e9+7;

int a[1000000];
int k,i,j,p,m,n;

int main()
{
    
      
    scanf("%d",&n);
    while(i<n)
    {
    
    
        m=1; k=0; p=0;
        for(j=0;j<100;j++) 	a[j]=0;
        while(m!=0)
        {
    
    
            scanf("%d",&m);
            a[m]++;
            k++;
        }
        for(j=1;j<k-1;j++)
        	if(a[j]%2!=0) 	p=1;
        	
        if(p==0)    printf("Yes\n");
        else	printf("No\n");
        
        i++;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Luoxiaobaia/article/details/107779231