T3线段树写挂,郁闷~!!!~
prob1:野区(buff)
题目大意:同2019.7.23的\(T3\)盛宴(\(party\))
\(WoCao\),原题写挂,不想说什么了
原题就不讲思路了,直接上代码(以后要注意分类的全面):
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define int long long
inline int read()
{
int x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
const int xx=4010;
int dis[xx][xx],vis[xx],que[xx];
int head[xx],nxt[xx<<1],to[xx<<1],cnt=0;
inline void add(int u,int v){nxt[++cnt]=head[u];to[cnt]=v;head[u]=cnt;}
inline void bfs(int g)
{
dis[g][g]=0;
vis[g]=g;
int hd=0,tl=-1;
que[++tl]=g;
while(hd<=tl)
{
int gg=que[hd++];
for(int j=head[gg];j;j=nxt[j])
{
int jj=to[j];
if(vis[jj]!=g)
{
vis[jj]=g;
dis[g][jj]=dis[g][gg]+1;
que[++tl]=jj;
}
}
}
}
signed main()
{
int n=in,m=in;
fur(i,1,m)
{
int x=in,y=in;
add(x,y);
add(y,x);
}
memset(dis,0x7f,sizeof(dis));
fur(i,1,n) bfs(i);
int s1=in,t1=in,p1=in;
int s2=in,t2=in,p2=in;
if(dis[s1][t1]>p1||dis[s2][t2]>p2)
{
printf("-1\n");
return 0;
}
int ans=dis[s1][t1]+dis[s2][t2];
fur(i,1,n) fur(j,1,n)
{
if(dis[s1][i]+dis[i][j]+dis[j][t1]<=p1&&dis[s2][i]+dis[i][j]+dis[j][t2]<=p2) ans=min(ans,dis[s1][i]+dis[s2][i]+dis[i][j]+dis[j][t1]+dis[j][t2]);
if(dis[s1][j]+dis[j][i]+dis[i][t1]<=p1&&dis[s2][i]+dis[i][j]+dis[j][t2]<=p2) ans=min(ans,dis[s1][j]+dis[s2][i]+dis[j][i]+dis[i][t1]+dis[j][t2]);
}
printf("%lld\n",m-ans);
return 0;
}
prob3:云顶之奕(cloud)
题目大意:已知\(n\)个二元组\((a_i,b_i)\),与定值\(w\),有两个变量\(p,q\),当有\(m_1\)个二元组满足\(b_i<=q\)时,对答案有\(m_1*q*w\)的贡献,而若其他二元组中有\(m_2\)个二元组满足\(a_i<=p\),将对答案有\(m_2*p\)的贡献,求当\(q\)分别等于\(1\)到\(max(b_i)+1\)时,答案的最大值
50分强力部分分:用桶排与链表维护二元组,用值域线段树维护答案,\(O(logn-n)\)地修改:
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define int long long
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=1e5+10;
struct linetree
{
int sz,ans;
linetree *son[2];
linetree():sz(0),ans(0)
{
son[0]=son[1]=NULL;
}
};
linetree *root,*ty,pool[xx<<2];
int res[xx],n,w,head[xx],nxt[xx],a[xx],wuhan[xx],mx=0,alll;
inline linetree *newlt()
{
*++ty=linetree();
return ty;
}
inline void up(linetree *k)
{
k->ans=0;
if(k->son[0]) k->ans=max(k->ans,k->son[0]->ans);
if(k->son[1]) k->ans=max(k->ans,k->son[1]->ans);
}
inline void add(linetree *k,int l,int r,int c)
{
++k->sz;
if(l==r)
{
k->ans=k->sz*wuhan[l];
return;
}
int mid=(l+r)>>1;
if(!k->son[0]) k->son[0]=newlt();
add(k->son[0],l,mid,c);
if(c>mid)
{
if(!k->son[1]) k->son[1]=newlt();
add(k->son[1],mid+1,r,c);
up(k);
}
else k->ans=max(k->son[0]->ans,k->ans);
}
inline void ade(int u,int v)
{
nxt[v]=head[u];
head[u]=v;
}
inline void sol()
{
int all=n;
fur(c,1,mx)
{
for(int j=head[c-1];j;j=nxt[j])
{
add(root,1,alll,a[j]);
--all;
}
res[c]=all*c*w+root->ans;
}
}
signed main()
{
n=in;w=in;
fur(i,1,n)
{
wuhan[i]=a[i]=in;
int y=in;
ade(y,i);
mx=max(mx,y);
}
sort(wuhan+1,wuhan+n+1);
alll=unique(wuhan+1,wuhan+n+1)-wuhan-1;
fur(i,1,n) a[i]=lower_bound(wuhan+1,wuhan+alll+1,a[i])-wuhan;
++mx;
ty=pool;
root=newlt();
sol();
fur(i,1,mx) printf("%lld ",res[i]);printf("\n");
return 0;
}
正解:分块+斜率优化(自己推柿子)
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jiba signed
#define K(j,i) (double)(d[i]-d[j])/(j-i)
inline int read()
{
int x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
const int xx=1e5+10;
const int yy=1e3+10;
int pos[xx],d[xx],cnt[xx],tp=0,mx=0;
int que[yy][yy],ls[yy],rs[yy],tag[yy],ans[yy],hd[yy],tl[yy];
int res[xx],n,w,a[xx],head[xx],nxt[xx];
inline int get(int k,int i){return tag[k]*i+d[i];}
inline void add(int u,int to){nxt[to]=head[u];head[u]=to;}
inline void build(int k)
{
d[rs[k]]=rs[k]*cnt[rs[k]];
fdr(i,rs[k]-1,ls[k]) d[i]=(d[i+1]/(i+1)+cnt[i])*i;
hd[k]=1,tl[k]=1;
fur(i,ls[k],rs[k])
{
while(K(i,que[k][tl[k]])<K(que[k][tl[k]],que[k][tl[k]-1])&&tl[k]>hd[k]) --tl[k];
que[k][++tl[k]]=i;
}
while(get(k,que[k][hd[k]])<get(k,que[k][hd[k]+1])&&hd[k]<tl[k]) hd[k]++;
ans[k]=get(k,que[k][hd[k]]);
}
inline void ad_tag(int k)
{
while(get(k,que[k][hd[k]])<get(k,que[k][hd[k]+1])&&hd[k]<tl[k]) hd[k]++;
ans[k]=get(k,que[k][hd[k]]);
}
inline void sol()
{
int all=n;
fur(i,1,tp)
{
for(int j=head[i-1];j;j=nxt[j])
{
--all;
++cnt[a[j]];
fur(k,1,pos[a[j]]-1) ++tag[k],ad_tag(k);
build(pos[a[j]]);
}
fur(j,1,pos[mx]) res[i]=max(res[i],ans[j]);
res[i]+=all*w*i;
}
}
jiba main()
{
n=in;w=in;
fur(i,1,n)
{
a[i]=in;
mx=max(mx,a[i]);
int y=in;
tp=max(tp,y);
add(y,i);
}
int tmp=sqrt(mx);
fur(i,1,mx)
{
pos[i]=(i-1)/tmp+1;
if(pos[i]!=pos[i-1]) ls[pos[i]]=i;
rs[pos[i]]=i;
}
tp++;
sol();
fur(i,1,tp) printf("%lld ",res[i]);printf("\n");
return 0;
}
prob2:跑得快(\(pdk\))
题目大意:斗地主(改),可单打,对子,三带二,炸弹(不算步数),顺子,双顺子,三顺子,求最小步
正解:\(DP\)+部分搜索,\(DP\)预处理单打,对子,三带二的情况,爆搜各种顺子
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jiba signed
inline int read()
{
int x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
int n,ans;
int f[7][9][13][25],cnt[14],upstair[14]={0,4,4,4,4,4,4,4,4,4,4,4,3,1};
inline void up(int &a,int b){a=a>b?b:a;}
inline void init()
{
fur(i,0,n/4+1) fur(j,0,n/3+1) fur(k,0,n/2+1) fur(l,0,n+1) if(i*4+j*3+k*2+l<=n)
{
if(i)
{
up(f[i][j][k][l],f[i-1][j][k][l]);
up(f[i][j][k][l],f[i-1][j+1][k][l+1]);
up(f[i][j][k][l],f[i-1][j][k+2][l]);
up(f[i][j][k][l],f[i-1][j][k][l+4]);
}
if(j)
{
up(f[i][j][k][l],f[i][j-1][k][l]+1);
if(k) up(f[i][j][k][l],f[i][j-1][k-1][l]+1);
if(l) up(f[i][j][k][l],f[i][j-1][k][l-1]+1);
if(l>=2) up(f[i][j][k][l],f[i][j-1][k][l-2]+1);
up(f[i][j][k][l],f[i][j-1][k+1][l+1]);
up(f[i][j][k][l],f[i][j-1][k][l+3]);
}
if(k)
{
up(f[i][j][k][l],f[i][j][k-1][l]+1);
up(f[i][j][k][l],f[i][j][k-1][l+2]);
}
if(l) up(f[i][j][k][l],f[i][j][k][l-1]+1);
}
}
inline void search(int w,int las)
{
if(w>=ans) return;
if(las==0) return;
int rest[5]={0,0,0,0,0};
fur(i,1,13) if(cnt[i]) rest[cnt[i]]++;
up(ans,w+f[rest[4]][rest[3]][rest[2]][rest[1]]);
fur(i,1,11)
{
if(cnt[i]>=3)
{
cnt[i]-=3;
int j=i+1;
while(j<=12&&cnt[j]>=3)
{
cnt[j]-=3;
search(w+1,las-(j-i+1)*3);
++j;
}
fur(q,i,j-1) cnt[q]+=3;
}
}
fur(i,1,10)
{
if(cnt[i]>=2&&cnt[i+1]>=2)
{
cnt[i]-=2;
cnt[i+1]-=2;
int j=i+2;
while(j<=12&&cnt[j]>=2)
{
cnt[j]-=2;
search(w+1,las-(j-i+1)*2);
++j;
}
fur(q,i,j-1) cnt[q]+=2;
}
}
fur(i,1,8)
{
if(cnt[i]&&cnt[i+1]&&cnt[i+2]&&cnt[i+3])
{
cnt[i]-=1;
cnt[i+1]-=1;
cnt[i+2]-=1;
cnt[i+3]-=1;
int j=i+4;
while(j<=12&&cnt[j])
{
cnt[j]-=1;
search(w+1,las-(j-i+1));
++j;
}
fur(q,i,j-1) cnt[q]+=1;
}
}
}
jiba main()
{
freopen("pdk.in","r",stdin);
freopen("pdk.out","w",stdout);
int t=in;n=in+1;
memset(f,0x3f,sizeof(f));
f[0][0][0][1]=0;
init();
while(t--)
{
memset(cnt,0,sizeof(cnt));
ans=23;
fur(i,1,n-1)
{
int x=in,y=in;
if(x==1) cnt[12]++;
else if(x==2) cnt[13]++;
else cnt[x-2]++;
}
fur(i,1,12)
{
if(cnt[i]<upstair[i])
{
++cnt[i];
search(0,n);
--cnt[i];
}
}
printf("%lld\n",ans);
}
return 0;
}