JZOJ 猫咪的进化
题目
有 n n n个单位时间,可以选择 v [ i ] v[i] v[i]的价值,或 v [ i ] 2 v[i]^2 v[i]2但是下一单位时间不能选择,问获得的最大价值
分析
分成三种情况,选,选平方和不选,dp即可,但是竟然卡double输入
代码
#include <cstdio>
#include <cctype>
#define rr register
#define ls (i&1)^1
using namespace std;
inline double max(double x,double y){return x>y?x:y;}
inline double iut(){
rr int ans1=0,ans2=0,len=1,f=1; rr char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans1=(ans1<<3)+(ans1<<1)+(c^48),c=getchar();
if (c=='.'){
c=getchar();
while (isdigit(c)) len=len*10,ans2=(ans2<<3)+(ans2<<1)+(c^48),c=getchar();
return f*(ans1+ans2*1.0/len);
}else return ans1*f;
}
double dp[2][3]; int n=iut();
signed main(){
for (rr int i=1;i<=n;++i){
rr double x=iut();
dp[i&1][0]=max(dp[ls][0],max(dp[ls][1],dp[ls][2]));
dp[i&1][1]=max(dp[ls][0],dp[ls][1])+x;
dp[i&1][2]=max(dp[ls][0],dp[ls][1])+x*x;
}
printf("%.4lf",max(dp[n&1][0],max(dp[n&1][1],dp[n&1][2])));
return 0;
}
JZOJ GF打Dota
题目
求最短路径和次短路径
分析
对于最短路径,直接spfa即可,但是对于次短路径,需要起点和终点都各跑一遍,然后枚举边求起点和终点到该边的距离,这样就能保证次短
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <deque>
#define rr register
using namespace std;
struct node{int y,w,next;}e[100001];
int n,k,dis[10001][2],v[10001],ls[10001],ans=707406378;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void spfa(int s,int p){
dis[s][p]=0; v[s]=1;
rr deque<int>q; q.push_back(s);
while (q.size()){
rr int x=q.front(); q.pop_front();
for (rr int i=ls[x];i;i=e[i].next)
if (dis[e[i].y][p]>dis[x][p]+e[i].w){
dis[e[i].y][p]=dis[x][p]+e[i].w;
if (!v[e[i].y]){
v[e[i].y]=1;
if (q.size()&&dis[e[i].y][p]<dis[q.front()][p]) q.push_front(e[i].y);
else q.push_back(e[i].y);
}
}
v[x]=0;
}
}
signed main(){
n=iut(); memset(dis,127/3,sizeof(dis));
for (rr int m=iut();m;--m){
rr int x=iut(),y=iut(),w=iut();
e[++k]=(node){y,w,ls[x]}; ls[x]=k;
e[++k]=(node){x,w,ls[y]}; ls[y]=k;
}
spfa(1,0);
if (!iut()) return !printf("%d",dis[n][0]);
else{
spfa(n,1);
for (rr int x=1;x<=n;++x)
for (rr int i=ls[x],t;i;i=e[i].next)
if ((t=dis[x][0]+dis[e[i].y][1]+e[i].w)>dis[n][0])
ans=ans<t?ans:t;
return !printf("%d",ans);
}
}
JZOJ 网站计划
题目
区间最大值
分析
zkw线段树,但是我比赛的时候打错了
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int mod=2011;
int n,m,bas=1,w[530001],p[530001],ans;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
signed main(){
n=iut(); m=iut(); while ((bas<<=1)<n+2);
for (rr int i=1;i<=n;++i) w[bas+i]=iut(),p[bas+i]=i;
for (rr int i=bas-1;i;--i){
if (w[i<<1]>w[i<<1|1]) w[i]=w[i<<1],p[i]=p[i<<1];
else w[i]=w[i<<1|1],p[i]=p[i<<1|1];
}
for (rr int i=1;i<=m;++i){
rr int x=iut(),y=iut(),t=0,poi=0,l,r;
for (l=x+bas-1,r=y+bas+1;l^r^1;l>>=1,r>>=1){
if ((~l&1)&&t<w[l^1]) t=w[l^1],poi=p[l^1];
if ((r&1)&&t<w[r^1]) t=w[r^1],poi=p[r^1];
}
ans=(ans+t*((x+y)%mod))%mod;
for (w[l=poi+bas]=0,l>>=1;l;l>>=1){
if (w[l<<1]>w[l<<1|1]) w[l]=w[l<<1],p[l]=p[l<<1];
else w[l]=w[l<<1|1],p[l]=p[l<<1|1];
}
}
return !printf("%d",ans);
}
JZOJ 选做作业
题目
由于作业的重要程度不同,有些作业要在做完了另外一些作业后做,选出要做的作业,来使人做完作业后心情最为高兴。
分析
那么这道题就是一个最大权闭合子图的问题,首先要用拓扑排序把环去掉,然后正点权连源点,负点权连汇点,边权是它们的绝对值,然后在原来的图边权都是无限大,这样跑一遍最小割,那剩下的图必然不连通,用正权和减去最小割即为答案
代码
#include <cstdio>
#include <cctype>
#include <queue>
#define rr register
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
struct node{int y,w,next;}e[4001]; int s,t,n,m,tot,ans,k=1;
queue<int>tq[501],q; int dis[501],ls[501],p[501],a[501];
inline signed iut(){
rr int ans=0,f=1; rr char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans*f;
}
inline void add(int x,int y,int w){
e[++k]=(node){y,w,ls[x]}; ls[x]=k;
e[++k]=(node){x,0,ls[y]}; ls[y]=k;
}
inline signed bfs(int s){
for (rr int i=1;i<=t;++i) dis[i]=0;
queue<int>q; q.push(s); dis[s]=1;
while (q.size()){
rr int x=q.front(); q.pop();
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].w>0&&!dis[e[i].y]){
dis[e[i].y]=dis[x]+1;
if (e[i].y==t) return 1;
q.push(e[i].y);
}
}
return 0;
}
inline signed dfs(int x,int now){
if (x==t||!now) return now;
rr int rest=0,f;
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
rest+=(f=dfs(e[i].y,min(now-rest,e[i].w)));
e[i].w-=f; e[i^1].w+=f;
if (now==rest) return rest;
}
if (!rest) dis[x]=0;
return rest;
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i){
a[i]=iut();
for (rr int t=iut();t;--t)
++ls[i],tq[iut()].push(i);
}
for (rr int i=1;i<=n;++i)
if (!ls[i]) q.push(i);
while (q.size()){
rr int x=q.front(),cnt=tq[x].size(); q.pop();
for (rr int i=1;i<=cnt;++i){
rr int y=tq[x].front();
tq[x].pop(); tq[x].push(y);
if (!(--ls[y])) q.push(y);
}
}
for (rr int i=1;i<=n;++i)
if (!ls[i]) p[i]=++tot;
else ls[i]=0;
s=tot+1,t=tot+2;
for (rr int i=1;i<=n;++i)
if (p[i]){
if (a[i]<0) add(p[i],t,-a[i]);
else add(s,p[i],a[i]),ans+=a[i];
while (tq[i].size()){
rr int y=tq[i].front(); tq[i].pop();
if (p[y]) add(p[y],p[i],23333333);
}
}
while (bfs(s)) ans-=dfs(s,23333333);
return !printf("%d",ans);
}