CF1845 D. Rating System [思维题+数形结合]

传送门:CF

[前题提要]:自己在做这道题的时候思路完全想错方向,导致怎么做都做不出来,看了题解之后感觉数形结合的思考方式挺好的(或者这种做法挺典的),故写篇题解记录一下


题目很简单,不再解释.先不考虑 k k k,想想是一种什么情况?很显然应该是跟下图一样是一个折线图的变化.
在这里插入图片描述
然后是一个很简单的事实:我们选取的K一定是前缀和的某一个值,更为准确的来说,应该是一个即将减少的一个前缀和值.这个结论自己把玩一下应该是不难发现的,简单的讲一下为什么是这样.因为对于一个即将减少的值来说,我们不妨选取这个值,因为这个值肯定比即将减少的那个值大,那为啥不选这个更大的值呢.而对于中间段的数来说,那些数只是中间值,两端点必然有一个点比它更为优秀.

那么现在随便选取一个端点作为我们的K,看看原图会发生什么情况
在这里插入图片描述
考虑选择的K的值为红横线.不难发现原本白色的折线因为现在K的出现需要往左上进行一个平移.
继续看蓝色的圈,我们会发现原本的平移还不够,我们需要将整个部分进行再一次平移.(因为懒所以没有进一步画出).

上面这段操作很重要,是这一道题的关键.仔细品一下上面的操作,我们就会发现后面那部分的贡献其实就是后缀最大后缀和(两个前缀和差其实就是后缀和啦),也就是当前位置开始的所有的后缀和的最大值.直接讲可能有点抽象,建议仔细看看上面的图的平移操作.数形结合一下很好理解.
PS:出现蓝圈的原因就是因为该后缀和更大.

那么这道题的解法也就呼之欲出了.考虑枚举每一个前缀和作为我们的K,然后计算一下贡献即可.

但是还存在一种特殊情况需要再仔细考虑一下:
在这里插入图片描述
对于上图的情况,我们会发现最后一段的后缀和贡献是负的,并且此时没办法进行平移.怎么解决?想一下平移的实际意义,不难发现应该令该贡献为0,也就是后缀最大值的初始值应该定义0

PS:仔细的同学可能会有点疑问,要是我之前的前缀和有比当前选的前缀和要小的怎么办,其实只要自己手模一下就会发现要是出现这种情况,虽然我们此时的计算贡献是错的,但是实际上,即使是对的,本情况也绝不会是最优解,故无所谓这种情况.


下面是具体的代码部分:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls (rt<<1)
#define rs (rt<<1|1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
inline void print(__int128 x){
	if(x<0) {putchar('-');x=-x;}
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
#define maxn 1000000
#define int long long
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];int rmax[maxn],sum[maxn];
signed main() {
	int T=read();
	while(T--) {
		int n=read();
		for(int i=1;i<=n;i++) {
			a[i]=read();
		}
		for(int i=1;i<=n;i++) {
			sum[i]=sum[i-1]+a[i];
		}
		rmax[n]=0;
		for(int i=n-1;i>=0;i--) {
			rmax[i]=max(rmax[i+1],sum[n]-sum[i]);
		}
		int maxx=sum[n],ans=sum[n];
		for(int i=0;i<n;i++) {
			if(sum[i]+rmax[i]>maxx) {
				maxx=sum[i]+rmax[i];
				ans=sum[i];
			}	
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UserCF是一种基于用户的协同过滤算法,可以用于推荐系统。下面是一个简单的Java实现示例: 1.首先,我们需要定义一个User类来存储用户信息,包括用户ID和评分列表: ```java public class User { private int userId; private Map<Integer, Double> ratings; public User(int userId) { this.userId = userId; ratings = new HashMap<>(); } public int getUserId() { return userId; } public void setRating(int itemId, double rating) { ratings.put(itemId, rating); } public Double getRating(int itemId) { return ratings.get(itemId); } public Set<Integer> getRatedItems() { return ratings.keySet(); } } ``` 2.然后,我们需要定义一个UserCF类来计算用户相似度和进行推荐: ```java public class UserCF { private List<User> users; public UserCF(List<User> users) { this.users = users; } // 计算用户相似度 public double similarity(User u1, User u2) { Set<Integer> commonItems = new HashSet<>(u1.getRatedItems()); commonItems.retainAll(u2.getRatedItems()); if (commonItems.size() == 0) { return 0; } double sum1 = 0, sum2 = 0, sum3 = 0; for (int itemId : commonItems) { double r1 = u1.getRating(itemId); double r2 = u2.getRating(itemId); sum1 += r1 * r2; sum2 += r1 * r1; sum3 += r2 * r2; } return sum1 / (Math.sqrt(sum2) * Math.sqrt(sum3)); } // 推荐物品 public List<Integer> recommend(User user, int n) { Map<Integer, Double> scores = new HashMap<>(); for (User other : users) { if (other.getUserId() == user.getUserId()) { continue; } double sim = similarity(user, other); if (sim <= 0) { continue; } for (int itemId : other.getRatedItems()) { if (user.getRating(itemId) != null) { continue; } double score = sim * other.getRating(itemId); scores.put(itemId, scores.getOrDefault(itemId, 0.0) + score); } } List<Integer> result = new ArrayList<>(scores.keySet()); result.sort((i1, i2) -> Double.compare(scores.get(i2), scores.get(i1))); return result.subList(0, Math.min(n, result.size())); } } ``` 3.最后,我们可以使用UserCF类来进行推荐: ```java public class Main { public static void main(String[] args) { List<User> users = new ArrayList<>(); User user1 = new User(1); user1.setRating(1, 4.0); user1.setRating(2, 3.0); user1.setRating(3, 5.0); users.add(user1); User user2 = new User(2); user2.setRating(2, 4.0); user2.setRating(3, 3.0); user2.setRating(4, 5.0); users.add(user2); User user3 = new User(3); user3.setRating(1, 5.0); user3.setRating(2, 2.0); user3.setRating(4, 4.0); users.add(user3); UserCF userCF = new UserCF(users); List<Integer> items = userCF.recommend(user1, 2); System.out.println(items); } } ``` 在上面的示例中,我们创建了三个用户,每个用户评分了一些物品。然后,我们使用UserCF类来计算用户相似度并进行推荐。在这个例子中,我们将向用户1推荐两个物品。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值