8.8

8.8模拟赛

T1

当时被环搞傻了。。。爆搜9分

正解:

思路:T当成次数限制,然后可以想到分层图我怎么想不到。。。又不见多识广了,显然,分层图是个DAG,然后拓扑排序换spfa...然后又顺理成章开始dp

首先 (最大点权)$mxT >= cT^2 $ 才有意义

化简一下 即 mx>=c*T ,mx最大为1000,c最小1,所以T最大1000

设$ f[i][j] $ 表示 第 i 天到 j 这个点,最多的钱

$ f[i][j]=f[i-1] [last_j]+val[j]-c(2t-1) $

last_j 反向存边即可

$ f[0][1] =0 $

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int N=1005;
int n,m,c,val[N],f[N][N],ans;
inline int read() {
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x;
}
inline void Max(int &x,int y){if(x<y) x=y;}
int hd[5005],nxt[5005],to[5005],tot;
inline void add(int x,int y) {
    to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
}
int main() {
	n=read(),m=read(),c=read();
	for(int i=1;i<=n;i++)
		val[i]=read();
	for(int i=1;i<=m;i++) {
		int x=read(),y=read();
		add(y,x);
	}
	memset(f,-1,sizeof(f));
    f[0][1]=0;
	for(int i=1;i<1000;i++)
		for(int x=1;x<=n;x++)
			for(int j=hd[x];j;j=nxt[j])
				if(f[i-1][to[j]]!=-1)
					Max(f[i][x],f[i-1][to[j]]+val[x]-c*(2*i-1));
	for(int i=0;i<1000;i++)
		Max(ans,f[i][1]);
	printf("%d\n",ans);
	return 0;
}

T2

玄学。。。并不大理解

有负数——搞个偏移量delta

枚举两边搞中间??

然后二维前缀和一样的东东???

https://www.luogu.com.cn/blog/Fighter/solution-p6006

#include <iostream>
#include <cstdio>
using namespace std;
const int delta=1e6+5;
const int M=6e6+5;
const int N=5005;
int n,q,a[N],st[N],top,cnt[M];
long long f[N][N];
inline int read() {
	int x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int main() {
	n=read(),q=read();
	for(int i=1;i<=n;i++)
		a[i]=read()+delta;
	for(int i=1;i<=n;i++) {
		while(top) cnt[st[top--]]=0;
		for(int j=i+1;j<=n;j++) {
			if(delta*3>a[i]+a[j])
				f[i][j]=cnt[delta*3-a[i]-a[j]];
			cnt[a[j]]++,st[++top]=a[j];
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
	while(q--) {
		int l=read()-1,r=read();
		printf("%lld\n",f[r][r]+f[l][l]-f[l][r]-f[r][l]);
	}
	return 0;
}

T3

首先——离散化

跳肯定比不跳优,但不确定怎么跳,所以dp出跳板最多省多少步数

2*n-跳板最多省的步数

dp[i]=max(dp[j])+w[i];

然后树状数组维护max(dp[j])——过(x1,y1)的时候更新dp[],过(x2,y2)加到树状数组里

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=4e5+10;
#define int long long
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,m,cnt,tot;
struct node{
    int x,y,id;
    bool end;
    node() {}
    node(int x_,int y_,int id_,bool f){x=x_,y=y_,id=id_,end=f;}
}p[N];
bool cmp(node a,node b) {
    if(a.x!=b.x) return a.x<b.x;
    if(a.y!=b.y) return a.y<b.y;
    return a.id<b.id;
}
int b[N],w[N],f[N];
bool vis[N];

int c[N];
void update(int pos,int v) {
    for(int i=pos;i<N;i+=i&(-i))
        c[i]=max(c[i],v);
}
int query(int pos) {
    int res=0;
    for(int i=pos;i;i-=i&(-i))
        res=max(res,c[i]);
    return res;
}
signed main() {
    n=read();m=read();
    for(int i=1,x1,x2,y1,y2;i<=m;i++) {
        x1=read();y1=read();x2=read();y2=read();
        w[i]=y2-y1+x2-x1;
        b[++tot]=x1;b[++tot]=y1;b[++tot]=x2;b[++tot]=y2;
        p[++cnt]=node(x1,y1,i,0);
        p[++cnt]=node(x2,y2,i,1);
    }
    sort(b+1,b+1+tot);
    int len=unique(b+1,b+1+tot)-b;
    for(int i=1;i<=cnt;i++) {
        p[i].x=lower_bound(b+1,b+1+len,p[i].x)-b;
        p[i].y=lower_bound(b+1,b+1+len,p[i].y)-b;
    }
    sort(p+1,p+1+cnt,cmp);
    for(int i=1;i<=cnt;i++) {
        int x=p[i].x,y=p[i].y,id=p[i].id;
        if(vis[id]) {
            update(y,f[id]);
            continue;
        }
        vis[id]=1;
        f[id]=query(y)+w[id];
    }
    int ans=0;
    for(int i=1;i<=m;i++)
        ans=max(ans,f[i]);
    printf("%lld\n",n-ans+n);
    return 0;
}
posted @ 2020-08-17 16:40  ke_xin  阅读(37)  评论(0编辑  收藏  举报