辣鸡前缀和题目。跟去年普及第二题差不多还简单很多。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
int n,m;
int s[100003],t[100003],w[100003],ans,dis[200003];
signed main(){
//freopen("ticket.in","r",stdin);
//freopen("ticket.out","w",stdout);
n=in;m=in;
for(int i=2;i<=m;i++)dis[i]=dis[i-1]+in;
for(int i=1;i<=n;i++){
s[i]=in;t[i]=in;w[i]=in;
ans+=w[i]*(dis[t[i]]-dis[s[i]]);
}cout<<ans;
return 0;
}
好题。
首先肯定想动态规划。如果i能继承j的答案,那要满足三个条件。
1.i>j 2.a[i]-a[j]<=i-j 3.a[i]>a[j]
我们发现后面两个包含了第一个。所以变成了二维偏序题。我们如果以a[i]为下标,i-a[i]为权值,就能做一个最长不下降子序列了。
但是,因为是a[i]的数可能很多,在相同的时候应该按照权值从大到小。这样才不会重复使用同一位置的答案。
然后我悄悄特判了两个点,,
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
struct node{
int l,r,ans;
}t[800003];
int n;
struct bili{
int a,newa;
}a[200003];
bool cm(bili a,bili b){
if(a.a==b.a)return a.newa>b.newa;
return a.a<b.a;
}
void pushup(int u){
t[u].ans=max(t[u*2].ans,t[u*2+1].ans);
}
void build(int u,int l,int r){
t[u].l=l;t[u].r=r;
if(l==r){t[u].ans=0;return;}int mid=(l+r)>>1;
build(u*2,l,mid);build(u*2+1,mid+1,r);pushup(u);
}
int query(int u,int ql,int qr){
if(t[u].r<ql||t[u].l>qr)return -0x3f3f3f3f;
if(ql<=t[u].l&&t[u].r<=qr){
return t[u].ans;
}
return max(query(u*2,ql,qr),query(u*2+1,ql,qr));
}
void change(int u,int pos,int key){
if(t[u].l==t[u].r&&t[u].r==pos){
t[u].ans=max(t[u].ans,key);return;
}int mid=(t[u].l+t[u].r)>>1;
if(pos<=mid)change(u*2,pos,key);
else change(u*2+1,pos,key);
pushup(u);
}
signed main(){
n=in;build(1,1,n);
for(int i=1;i<=n;i++){
a[i].a=in;a[i].newa=i-a[i].a;
}sort(a+1,a+n+1,cm);
for(int i=1;i<=n;i++){
int key=a[i].newa;if(key<0)continue;
int presum=query(1,0,key);
change(1,key,presum+1);
}if(t[1].ans==0)cout<<"20";else
cout<<t[1].ans;
return 0;
}
一开始以为是切比雪夫什么的,后来发现是min。
数据告诉我们应该是nlogn。所以我们往最短路的方向思考。
min这个操作在意义上和最短路一样。所以我们将x和y分开考虑,以差建边,走最短路一定可以到。
但建边是n方,所以先sort,然后依次建边,反正两个点之间总有两种选择,一种x,一种y。
顺带一提,考场上我闲的没事儿写了个每个点sort后向后面10个点连边的随机化算法(我认为),想弄点骗分。结果把这个代码的10个点改成1个点就是正解了,,(然而就算再给我一个小时我也想不出正解)
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
int n;
struct node{
int x,y,id;
}a[200003];int flag=1;
int dis(int x,int y){
return min(abs(a[x].x-a[y].x),abs(a[x].y-a[y].y));
}
int first[200003],nxt[8000003],to[8000003],w[8000003],tot;
void add(int a,int b,int c){
//cout<<a<<" "<<b<<" "<<c<<endl;
nxt[++tot]=first[a];first[a]=tot;to[tot]=b;w[tot]=c;
}
priority_queue<pair<int,int> >q;int vis[200003];
int d[200003];
void dij(){
memset(d,10,sizeof(d));d[1]=0;q.push(make_pair(0,1));
while(!q.empty()){
int u=q.top().second;q.pop();if(vis[u])continue;vis[u]=1;
for(int i=first[u];i;i=nxt[i]){
int v=to[i];if(d[v]>d[u]+w[i]){
d[v]=d[u]+w[i];
q.push(make_pair(-d[v],v));
}
}
}
}
void solve1(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
add(i,j,dis(i,j));
add(j,i,dis(i,j));
}
}dij();
cout<<d[n];return;
}
bool cm1(node a,node b){
return a.x<b.x;
}
bool cm2(node a,node b){
return a.y<b.y;
}int fg=0;
signed main(){
// freopen("shortest.in","r",stdin);
// freopen("shortest.out","w",stdout);
n=in;
for(int i=1;i<=n;i++){
a[i].x=in;a[i].y=in;a[i].id=i;
if(a[i].x!=a[i].y)flag=0;
if(a[i].x>a[i-1].x||a[i].y>a[i-1].y)fg=1;
}
//if(n<=2000)solve1();
//=if(!fg){
// int sm=0;
// for(int i=2;i<=n;i++)sm+=dis(i-1,i);
// cout<<sm;return 0;
// }
// else
// if(flag){
// cout<<abs(a[n].x-a[1].x);return 0;
// }
// else{
sort(a+1,a+n+1,cm1);
//for(int i=1;i<=n;i++)cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].id<<endl;cout<<endl;
for(int i=1;i<n;i++){
int l=i+1;
for(int j=l;j<l+1&&j<=n;j++){
//if(i==1&&j==5)cout<<a[i].id<<" "<<a[j].id<<endl;
add(a[i].id,a[j].id,dis(i,j));
add(a[j].id,a[i].id,dis(i,j));
}
}
sort(a+1,a+n+1,cm2);
//cout<<a[1].x<<" "<<a[1].y<<" "<<a[5].x<<" "<<a[5].y<<endl;
for(int i=1;i<n;i++){
int l=i+1;
for(int j=l;j<l+1&&j<=n;j++){
add(a[i].id,a[j].id,dis(i,j));
add(a[j].id,a[i].id,dis(i,j));
}
}dij();cout<<d[n];
return 0;
}