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;
}