阿里7.27笔试思路

两道题都是结束以后才想出来。。。两题都只过了20%,哭了。
第一题应该是只有当所有数字都出现偶数次时候第二个人才能赢,其他情况都是第一个人赢。
第二题我以为是只能取每一层的一头一尾两个,写了一个dp,只过了20%,结束以后我发现数据给的n和c最大为100,m最大为10000,说明如果m >= n * c,所有物品都可以拿走,所以每一层如果已经拿了第1个和第c个,那就还可以继续拿第2个和第c-1个。
个人觉得是个背包dp,然后时间不够呀!!!
好气!结束了才想到。

(代码有问题。。。不好意思,我删掉重写)

昨晚躺在床上突然发现之前这样子贪心找到的并不是最优解,思来想去,发现可以用滑动窗口预处理出当前层取x个物品可以获得的最大价值存在数组中,然后dp,复杂度O(n*(c^2+m*c)),我觉得应该没有问题,欢迎大家指正!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[110], val[110];
int dp[10010];
int main()
{
	int n, m, c;
	cin >> n >> m;
	memset(dp, 0, sizeof dp);
	for (int i = 0; i < n; i++){
		int sum = 0;//求当前层物品价值和
		cin >> c;
		for (int j = 0; j < c; j++){
			cin >> a[j];
			sum += a[j];
		}
		memset(val, 0, sizeof val);
		for (int k = 1; k <= c; k++){ // 当前层获得k件物品可得的最大值存入val
			int index = 0, now = 0;//滑动窗口,窗口大小为c-k
			while (index < c-k){
				now += a[index];
				index++;
			}
			val[k] = max(val[k], sum-now);
			while (index < c){
				now += a[index];
				now -= a[index-c+k];
				val[k] = max(val[k], sum-now);
				index++;
			}
		}
		for (int j = m; j > 0; j--)
			for (int k = 1; k <= min(j, c); k++)
				dp[j] = max(dp[j], dp[j-k]+val[k]);
	}
	cout << dp[m] << endl;
	return 0;
}


#阿里巴巴#
全部评论
第二题两端拿掉了,中间暴露出来还可以拿中间的吗!完蛋,题目都没懂
1 回复 分享
发布于 2020-07-27 20:34
第一题博弈,直接看最后出现的数字次数是奇数则先手赢,偶数则后手赢; 第二题感觉是dp但是不会= =直接用贪心混20分
1 回复 分享
发布于 2020-07-27 20:42
public static void main(String[] args){     int n,m,c;     n=sc.nextInt();     m=sc.nextInt();     for(int i=0 ; i<n ; i++ ){         int sum=0;// 求该层的物品价值总和         c=sc.nextInt();         for(int j=0 ; j<c ; j++ ){             a[j] = sc.nextInt();             sum+=a[j];         }         Arrays.fill(val,0);         for(int k=1 ; k<=c ; k++){ // 当前层获得k件物品可得的最大值存入val             int index= 0 , now = 0;// 滑动窗口,窗口大小为c-k             while(index < c-k)// 初始窗口 从第一个开始累加                 now +=a[index++];             val[k] = Math.max(val[k],sum-now);             while(index<c){ // 开始往右边移动                 now+= a[index];                 now-=a[index-(c-k)];                 val[k] = Math.max(val[k],sum-now); //求的是窗口以外的数和最大值                 index++;             }         }         // 此时该层的val已经求出 01背包求解         for(int j=m ; j>0 ; j--){             for(int k=1 ; k<= Math.min(j,c) ; j++ )                 dp[j] = Math.max(dp[j],dp[j-k]+val[k]);         }     }       System.out.println(dp[m]); }
1 回复 分享
发布于 2020-07-28 15:23
我0%
点赞 回复 分享
发布于 2020-07-27 20:29
第一题过了 第二题没写出来 dp不知道怎么设计 感觉复杂度爆表
点赞 回复 分享
发布于 2020-07-27 20:29
草,第一题这么简单,我就是一个测试样例都过不了,哎
点赞 回复 分享
发布于 2020-07-27 20:30
求讲第二题思路
点赞 回复 分享
发布于 2020-07-27 20:30
草原来是这样,我也是20%
点赞 回复 分享
发布于 2020-07-27 20:32
第一题输出,我没明白;T个测试用例,是每个测试用例都cout<<"NIUNIU"或者“NIUMEI”<<endl;(我的思路和楼主一样,但是输入输出没搞定~)😥
点赞 回复 分享
发布于 2020-07-27 20:35
a了1点2🤣,第二题感觉都没读懂题瞎混了20%
点赞 回复 分享
发布于 2020-07-27 20:37
请问有原题吗
点赞 回复 分享
发布于 2020-07-27 21:35
你单独每一层的dp状态写错了  1 4 6 10 2 2 10 1 5 这样的数据你肯定过不了
点赞 回复 分享
发布于 2020-07-27 23:19
Java怎么写第二题的输入啊。。。我用常规Scanner套路 用两层for循环 想第一层写宝箱数量 第二层写宝物价值。 内循环循环完一次直接报错😂 有大佬可以告诉我应该怎么写吗? 我太蔡了
点赞 回复 分享
发布于 2020-07-28 00:44
我不知道我理解题意对不对,我想的是弄一个新类记录每个物品所在位置以及价值,我就把所有层头尾两个数放到大根堆PQ(按价值排序)里,完了每次把顶上的值拿出来,按照他的位置去把他后面或者前面新暴露出来的点放进去,一直做M次,这样,请做过的大佬指点一下,谢了。
点赞 回复 分享
发布于 2020-07-28 09:48
如果先做预处理将每层的取j个的最优情况 放在vector<vector<int>>value;中, value[i][j]代表在第i层取j个的最优解,做出这样的二维数组,时间复杂度是O(100*10000);每一层是O(10000),最多100层, 然后可以用动态规划。 dp[i][j] 表示到第i层,取j个,的最优解,   那么dp[i][j]等于,dp[i-1][j-x]+value[i][x];x是0->j;就是前面用0个,这层用j个,前面用1个这层用j-1个。。。的最优解, 然后时间复杂度是 O(100*100*100),第一个是一共100层,第二个是 j最多取道100个,第三个是从 0-j,1-j-1...j-0;一共比较100次。 所以最后的时间复杂度是O(1百万); 欢迎指正。
点赞 回复 分享
发布于 2020-07-28 13:46
获取val的第k个 能否用双指针指向两边,然后不断往中间移,进行存储呢?感觉这个滑动窗口有点看不懂。。。
点赞 回复 分享
发布于 2020-07-28 14:21
感觉就是这个思路,先生成每层的取用数组,然后再从上到下根据取用数组生成dp数组,最后遍历最后一层dp数组获得结果。
点赞 回复 分享
发布于 2020-07-29 12:32

相关推荐

独特的大学生想当offer收割机:浪潮赚钱省立花,一分别想带回家
点赞 评论 收藏
分享
点赞 13 评论
分享
牛客网
牛客企业服务