省选专练IOI2000邮局(S4共享单车)

第一次秒掉IOI的题

啥?数字三角形?

第一,很明显n^3可以过,那不就水了吗?

但事实上村庄带权依旧可做

而且有朴素的n^2*logn做法

甚至整体二分或是决策单调性都可以AC

而且复杂度为严格的nlogn

所以水过啊

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef  int INT;
#define int long long 
const int INF=1e18;
int f[60000][35]={0};
int p_sum_a[60000]={0};
int p_sum_l[60000]={0};
int p_sum[60000]={0};
int s_sum_a[60000]={0};
int s_sum_l[60000]={0};
int s_sum[60000]={0};
int a[60000]={0};
int p_l[60000]={0};
int s_l[60000]={0};
int n,k;
int getsum(int l,int r){
	if(l==r)
		return 0;
	if(l<r)
		return p_sum[r]-p_sum[l]-(p_sum_l[r]-p_sum_l[l])*(l?p_sum_a[l-1]:0);
	else{
		swap(l,r);
//		cout<<s_sum[l]<<" "<<s_sum[r]<<endl;
		return s_sum[l]-s_sum[r]-(s_sum_l[l]-s_sum_l[r])*(r==n?0:s_sum_a[r+1]);
	}
}
int judge(int x,int y){
	if(y-x<=1){
		return 0;
	}
	int half=(p_sum_l[x]+p_sum_l[y])/2;
	int pos=lower_bound(p_sum_l+1,p_sum_l+1+n,half)-p_sum_l;
//	cout<<pos<<endl;
	if(p_sum_l[pos-1]==half)
		pos--;
//	cout<<pos<<" "<<getsum(pos,y)<<" "<<getsum(pos-1,x)<<endl;
	return getsum(pos,y)+getsum(pos-1,x);
}
int dis_C[60001]={};
INT main(){
//	freopen("bike.in","r",stdin);
//	freopen("bike.out","w",stdout);
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		a[i]=1;
		scanf("%d",&dis_C[i]);
	}
//	for(int i=1;i<=)
	for(int i=2;i<=n;i++){
		p_l[i]=dis_C[i]-dis_C[i-1];
//		scanf("%d",&p_l[i]);
		s_l[i-1]=p_l[i];
	}
	for(int i=1;i<=n;i++){
		p_sum_a[i]=p_sum_a[i-1]+a[i];
	}
	for(int i=n;i>=1;i--){
		s_sum_a[i]=s_sum_a[i+1]+a[i];
	}
	for(int i=1;i<=n;i++){
		p_sum_l[i]=p_sum_l[i-1]+p_l[i];
	}
	for(int i=n-1;i>=0;i--){
		s_sum_l[i]=s_sum_l[i+1]+s_l[i];
	}
	for(int i=2;i<=n;i++){
		p_sum[i]=p_sum[i-1]+p_sum_a[i-1]*p_l[i];
	}
	for(int i=n-1;i>=1;i--){
		s_sum[i]=s_sum[i+1]+s_sum_a[i+1]*s_l[i];
	}
//	for(int i=n;i>=1;i--){
//		cout<<s_sum[i]<<" ";
//	}
//	cout<<" kkk "<<judge(0,2);
//	cout<<endl<<"-0-0-0-0-"<<endl;
	memset(f,63,sizeof(f));
	for(int i=0;i<=n;i++){
		f[i][0]=0;
		f[i][1]=p_sum[i];
	}
//	cout<<getsum(5,4);
	for(int i=2;i<=k;i++){
		for(int j=1;j<=n;j++){
			for(int ii=1;ii<j;ii++){
//				cout<<j<<" "<<i<<" "<<" "<<ii<<" "<<f[ii][i-1]<<" "<<judge(ii,j)<<endl;
				f[j][i]=min(f[j][i],f[ii][i-1]+judge(ii,j));
			}
		}
	}
//	cout<<"----"<<endl;
	/*for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			cout<<f[i][j]<<" ";
		}
		cout<<endl;
	}*/
	int ans=INF;
	for(int i=k;i<=n;i++){
//		cout<<f[i][k]<<" "<<getsum(n,i)<<endl;
		ans=min(ans,f[i][k]+getsum(n,i));
	}
	cout<<ans;
	return 0;
} 

附带权的题目(考场只写了60)


带权可过n=1e5代码

#include<bits/stdc++.h>
using namespace std;
typedef int INT;
#define int long long
#define insert Insert
#define LL long long
const int N=2e5+100;
const int INF=1e17;
int suma[N]={0};
int sumf[N]={0};
int sum[N]={0};
int g[N][23];
int f[N][23];
int n,k;
struct hh{LL x,y;};
double suan(hh a,hh b)
{
	if(b.x-a.x==0){return (b.y>a.y)?INF:-INF;}
	return (double)(b.y-a.y)/(b.x-a.x);
}
struct que1
{
	hh q[N];int l,r;
	que1(){l=1;r=0;}
	void pop(LL x){while(l<r&&suan(q[l],q[l+1])<x)l++;}
	void insert(hh a)
	{
		while(l<r&&suan(q[r-1],q[r])>=suan(q[r],a))r--;
		q[++r]=a;
	}
	hh top(){return q[l];}
}q1[21],q2[21];
/*struct Node{
	int x,y;
}q[N];
double judge(Node A,Node B){
	if(A.x==B.x){
		return B.y>A.y?INF:-INF;
	}
	return (double)(B.y-A.y)/(B.x-A.x);
}
struct humdrum_queue{
	int head,tail;
	humdrum_queue(){head=1;tail=0;}
	void pop(int x){while(head<tail&&judge(q[head],q[head+1])<x)head++;}
	void Insert(Node A){
		while(head<tail&&judge(q[tail-1],q[tail])>=judge(q[tail],A))
			tail--;
		q[++tail]=A;
	}
	Node top(){return q[head];}*/
//}q1[21],q2[21];
INT main(){
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;++i)
		scanf("%lld",&suma[i]);
	for(int i=2;i<=n;++i)
		scanf("%lld",&sum[i]),sum[i]+=sum[i-1];
	for(int i=1;i<=n;++i)
		sumf[i]=suma[i]*sum[i]+sumf[i-1],suma[i]+=suma[i-1];
	/*scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%lld",&suma[i]);
	}
	for(int i=2;i<=n;i++){
		scanf("%lld",&sum[i]);
		sum[i]+=sum[i-1];
	}
	for(int i=1;i<=n;i++){
		sumf[i]=suma[i]*sum[i]+sumf[i-1];
		suma[i]+=suma[i-1];
	}*/
	for(int i=0;i<=k;++i)
		q1[i].Insert((hh){suma[0],g[0][i]+sumf[0]}),q2[i].Insert((hh){sum[0],f[0][i]-sumf[0]+suma[0]*sum[0]});
	for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			q1[j-1].pop(sum[i]);hh now=q1[j-1].top();
			f[i][j]=now.y-now.x*sum[i]+suma[i]*sum[i]-sumf[i];
			q2[j].pop(suma[i]);now=q2[j].top();
			g[i][j]=now.y-now.x*suma[i]+sumf[i];
			g[i][j]=min(g[i][j],f[i][j]);
			q1[j].Insert((hh){suma[i],g[i][j]+sumf[i]});
			q2[j].Insert((hh){sum[i],f[i][j]-sumf[i]+suma[i]*sum[i]});			
			/*q1[j-1].pop(sum[i]);
			Node now=q1[j-1].top();
			f[i][j]=now.y-now.x*sum[i]+suma[i]*sum[i]-sumf[i];
			q2[j].pop(suma[i]);
			now=q2[j].top();
			g[i][j]=now.y-now.x*suma[i]+sumf[i];
			g[i][j]=min(g[i][j],f[i][j]);
			q1[j].Insert((Node){suma[i],g[i][j]+sumf[i]});
			q2[j].Insert((Node){sum[i],f[i][j]-sumf[i]+suma[i]*sum[i]});*/
		}
	}
	int ans=g[n][k];
	for(int i=1;i<=k;i++){
		ans=min(ans,g[n][i]);
	}
	cout<<ans;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值