联考B卷
Day1T1卡牌游戏
把前缀和中正的加起来即可,复杂度为\(O(N)\)(难道这题都不会的能去sx?)
//μ's forever
#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int n,a[N];
ll sum[N],ans;
int main()
{
n=read();
for(register int i=1;i<=n;++i)
a[i]=read(),sum[i]=0ll+sum[i-1]+a[i];
for(register int i=2;i<=n;++i)
if(sum[i]>0)
ans+=sum[i];
write(ans);
return 0;
}
Day1T2消息传递
比较裸的一个点分治,每次分治记录\(p[i]\)表示到分治中心(重心)距离为\(i\)的点的个数,对答案的贡献计算也非常simple,所有长度为k-dep[x]的点数减去在同一子树里的,复杂度为\(O(Tn\log n)\)
//μ's forever
#include <bits/stdc++.h>
#define N 100005
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct edge{
int to,nxt;
}e[N<<1];
int head[N],cnt=0;
inline void add(register int u,register int v)
{
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int T,n,m,ans[N],f[N],rt,siz[N],ms,vis[N],dep[N],sta[N],top=0,st[N],ed[N],p[N];
vector<pair<int,int> > q[N];
inline void getrt(register int x,register int fa)
{
f[x]=0,siz[x]=1;
for(register int i=head[x];i;i=e[i].nxt)
{
int v=e[i].to;
if(vis[v]||v==fa)
continue;
getrt(v,x);
f[x]=max(f[x],siz[v]);
siz[x]+=siz[v];
}
f[x]=max(f[x],ms-siz[x]);
if(f[x]<f[rt])
rt=x;
}
inline void dfs(register int x,register int fa)
{
sta[++top]=x;
st[x]=top;
for(register int i=head[x];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa||vis[v])
continue;
dep[v]=dep[x]+1;
dfs(v,x);
}
ed[x]=top;
}
inline void solve(register int x)
{
vis[x]=1,dep[x]=0;
dfs(x,0);
for(register int i=1;i<=top;++i)
++p[dep[sta[i]]];
for(register int i=0;i<q[x].size();++i)
ans[q[x][i].second]+=p[q[x][i].first];
for(register int i=head[x];i;i=e[i].nxt)
{
int v=e[i].to;
if(vis[v])
continue;
for(register int j=st[v];j<=ed[v];++j)
--p[dep[sta[j]]];
for(register int j=st[v];j<=ed[v];++j)
for(register int k=0;k<q[sta[j]].size();++k)
if(q[sta[j]][k].first>=dep[sta[j]])
ans[q[sta[j]][k].second]+=p[q[sta[j]][k].first-dep[sta[j]]];
for(register int j=st[v];j<=ed[v];++j)
++p[dep[sta[j]]];
}
while(top)
--p[dep[sta[top--]]];
for(register int i=head[x];i;i=e[i].nxt)
{
int v=e[i].to;
if(vis[v])
continue;
rt=0;
ms=siz[v];
getrt(v,0);
solve(rt);
}
}
int main()
{
T=read();
while(T--)
{
memset(head,0,sizeof(head));
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
cnt=0;
n=read(),m=read();
for(register int i=1;i<n;++i)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
for(register int i=1;i<=m;++i)
{
int x=read(),k=read();
q[x].push_back(make_pair(k,i));
}
rt=0;
f[rt]=ms=n;
getrt(1,0);
solve(rt);
for(register int i=1;i<=m;++i)
write(ans[i]),puts("");
for(register int i=1;i<=n;++i)
q[i].clear();
}
return 0;
}
Day1T3冰火战士
发现随着温度的升高,可用冰战士能量之和不降,可用火战士能量之和不升
题目要求的是两者中较小值的两倍,那么显然两函数交点最优
求交点不难想到做差,然后再数据结构上查零点(此处零点指当\(ice<fire/ice>fire\)时,\(fire-ice/ice-fire\)最小值的点)
普通的二分零点再判断的算法是\(O(n \log^2 n)\)的,并不能通过此题
这里应该通过倍增的手法来找到这个零点,从0的位置开始,每次加\(2^n,2^{n-1},……,2^0\),加上的正好就是新值的\(lowbit\),这样可以\(O(1)\)更新差值并判断
这样就能在\(O(n\log n)\)时间内解决本题
//μ's forever
#include <bits/stdc++.h>
#define N 2000005
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct bit{
int ic[N],fr[N],sz,del=0;
inline void modifyic(register int x,register int val)
{
for(register int i=x;i<=sz;i+=(i&(-i)))
ic[i]+=val;
}
inline void modifyfr(register int x,register int val)
{
del+=val;
for(register int i=x+1;i<=sz;i+=(i&(-i)))
fr[i]-=val;
}
inline int qrym(register int x)
{
int sic=0,sfr=del;
for(register int i=x;i;i-=(i&(-i)))
sic+=ic[i],sfr+=fr[i];
return min(sic,sfr);
}
inline int fd1()
{
int res=0,dis=-del;
for(register int i=20;i>=0;--i)
{
if(res+(1<<i)>sz)
continue;
int tmp=dis+ic[res+(1<<i)]-fr[res+(1<<i)];
if(tmp<0)
{
dis=tmp;
res+=(1<<i);
}
}
return res;
}
inline int fd2(register int exp)
{
int res=0,sic=0,sfr=del;
for(register int i=20;i>=0;--i)
{
if(res+(1<<i)>sz)
continue;
int tmp1=sic+ic[res+(1<<i)],tmp2=sfr+fr[res+(1<<i)];
if(tmp1<tmp2)
{
res+=(1<<i);
sic=tmp1,sfr=tmp2;
}
else if(min(tmp1,tmp2)==exp)
{
res=res+(1<<i);
sic=tmp1,sfr=tmp2;
}
}
return res;
}
}tr;
struct node{
int ty,tp,en;
}q[N];
int Q,val[N],cnt=0;
int main()
{
Q=read();
for(register int i=1;i<=Q;++i)
{
int x=read();
if(x==1)
{
q[i].ty=read(),q[i].tp=read(),q[i].en=read();
val[++cnt]=q[i].tp;
}
else
{
int k=read();
q[i].ty=q[k].ty,q[i].tp=q[k].tp,q[i].en=-q[k].en;
}
}
sort(val+1,val+cnt+1);
int ns=unique(val+1,val+cnt+1)-val-1;
tr.sz=ns;
for(register int i=1;i<=Q;++i)
q[i].tp=lower_bound(val+1,val+ns+1,q[i].tp)-val;
for(register int i=1;i<=Q;++i)
{
if(q[i].ty==0)
tr.modifyic(q[i].tp,q[i].en);
else
tr.modifyfr(q[i].tp,q[i].en);
pair<int,int> ans;
int ip1=tr.fd1();
ans=make_pair(tr.qrym(ip1),ip1);
if(ip1<ns)
{
int exp=tr.qrym(ip1+1);
if(exp>=ans.first)
{
int ip2=tr.fd2(exp);
ans=make_pair(exp,ip2);
}
}
if(ans.first==0)
puts("Peace");
else
write(val[ans.second]),putchar(' '),write(ans.first<<1),puts("");
}
return 0;
}
Day2T1幸运数字
离散化后进行差分,在前缀异或和上找答案,时间复杂度为\(O(n \log n)\)
//μ's forever
#include <bits/stdc++.h>
#define N 100005
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct node{
int tp,a,b,c;
}q[N];
int n,val[N<<1],cnt,tg[N<<1],ans,cur;
int main()
{
n=read();
val[++cnt]=-2000000000;
val[++cnt]=0;
for(register int i=1;i<=n;++i)
{
q[i].tp=read();
if(q[i].tp==1)
{
q[i].a=read(),q[i].b=read(),q[i].c=read();
val[++cnt]=q[i].a,val[++cnt]=q[i].b+1;
}
else
{
q[i].a=read(),q[i].b=read();
val[++cnt]=q[i].a,val[++cnt]=q[i].a+1;
}
}
sort(val+1,val+1+cnt);
int sz=unique(val+1,val+1+cnt)-val-1;
for(register int i=1;i<=n;++i)
{
if(q[i].tp==1)
{
int posa=lower_bound(val+1,val+sz+1,q[i].a)-val,posb=lower_bound(val+1,val+sz+1,q[i].b+1)-val;
tg[posa]^=q[i].c,tg[posb]^=q[i].c;
}
else
{
int posa=lower_bound(val+1,val+sz+1,q[i].a)-val,posb=posa+1;
tg[posa]^=q[i].b,tg[posb]^=q[i].b;
if(q[i].tp==3)
tg[1]^=q[i].b;
}
}
for(register int i=1,tmp=0;i<=sz;++i)
{
tmp^=tg[i];
if(tmp>cur)
{
cur=tmp;
if(val[i]<0)
ans=val[i+1]-1;
else
ans=val[i];
}
else if(tmp==cur)
{
if(val[i]<0)
ans=val[i+1]-1;
else if(val[i]<=fabs(ans))
ans=val[i];
}
}
printf("%d %d\n",cur,ans);
return 0;
}
Day2T2信号传递
记\(cnt[i][j]\)表示从\(i\)到\(j\)共有几个
考虑状压dp,设\(f[S]\)表示用了\(S\)集合里的数,考虑了编号为前\(|S|\)的信号站
考虑第\(pos=|S|+1\)个位置,选用了一个没选过的数\(i\),经过推柿子,可以得到一下转移
这是个\(O(2^m m^2)\)的暴力,考虑优化
我们发现后面这一大串实际珂以预处理,又其他状态快速转移得来,得到一个\(O(2^m m)\)的做法,可惜这样会MLE
这里dyls教了我一个手法,用队列来滚动优化,这样就得到了\(O(2^m m)\)的正解
//μ's forever
#include <bits/stdc++.h>
#define N 100005
#define M 23
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct node{
int sta,v[M];
};
queue<node> q;
int n,m,k,s[N],cnt[M][M];
int bitc[1<<M],id[1<<M],f[1<<M];
int main()
{
n=read(),m=read(),k=read();
for(register int i=1;i<=n;++i)
s[i]=read()-1;
for(register int i=1;i<n;++i)
++cnt[s[i]][s[i+1]];
int Ms=(1<<m)-1;
for(register int i=0;i<m;++i)
id[1<<i]=i;
for(register int i=1;i<=Ms;++i)
bitc[i]=bitc[i>>1]+(i&1),f[i]=1145141919;
node tmp;
tmp.sta=0;
for(register int i=0;i<m;++i)
{
tmp.v[i]=0;
for(register int j=0;j<m;++j)
if(j!=i)
tmp.v[i]+=k*cnt[j][i]-cnt[i][j];
}
q.push(tmp);
while(!q.empty())
{
node a=q.front();
q.pop();
int nxtbitc=bitc[a.sta]+1;
for(register int i=a.sta^Ms;i;i-=i&(-i))
{
int nf=f[a.sta],nsta=a.sta|(i&(-i));
nf+=nxtbitc*a.v[id[i&(-i)]];
f[nsta]=min(f[nsta],nf);
}
for(register int i=0;i<m;++i)
{
if((a.sta>>i)&1)
break;
node nsta;
nsta.sta=a.sta|(1<<i);
for(register int j=nsta.sta^Ms;j;j-=j&(-j))
nsta.v[id[j&(-j)]]=a.v[id[j&(-j)]]+k*cnt[id[j&(-j)]][i]+cnt[i][id[j&(-j)]]-k*cnt[i][id[j&(-j)]]+cnt[id[j&(-j)]][i];
q.push(nsta);
}
}
printf("%d\n",f[Ms]);
return 0;
}
Day2T3丁香之路
考虑每次走的路线,应该是必走的边和自己添加的一些边的"欧拉路",起点和终点为奇点,其他点为偶点(先这样理解,此处欧拉路只是个广义的理解,不是真正的欧拉路)
程序中把起点和终点度数加一,再按顺序匹配相邻的奇点,给答案加上这条边,这样就结束了?
还没完,这个图只是定义上满足欧拉路,但不保证连通。用并查集维护连通块,之前连接的两奇点与之间偶点能合并成一个连通块。我们对有的连通块之间求距离,找出最小生成树,给答案加上边权和的两倍,显然这里能成为最小生成树的边是编号相邻两点间的
这样我们就在\(O((m+n^2) \log n)\)的时间内解决了问题
//μ's forever
#include <bits/stdc++.h>
#define ll long long
#define N 2505
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int n,m,s,fa[N],in[N];
vector<int> v[N];
inline int find(register int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
struct node{
int u,v,w;
bool operator < (const node &a) const{
return w<a.w;
}
};
int main()
{
n=read(),m=read(),s=read();
ll sum=0;
for(register int i=1;i<=n;++i)
fa[i]=i;
for(register int i=1;i<=m;++i)
{
int s=read(),t=read();
v[s].push_back(t),v[t].push_back(s);
sum+=fabs(s-t);
fa[find(s)]=find(t);
}
for(register int i=1;i<=n;++i)
in[i]=find(i);
for(register int i=1;i<=n;++i)
{
for(register int j=1;j<=n;++j)
fa[j]=j;
v[s].push_back(i),v[i].push_back(s);
int pre=0;ll ans=sum;
for(register int j=1;j<=n;++j)
if(v[j].size()&1)
{
if(pre)
{
ans+=j-pre;
for(register int k=pre;k<j;++k)
fa[find(in[k])]=find(in[j]);
pre=0;
}
else
pre=j;
}
vector<node> e;
for(register int j=1;j<=n;++j)
if(v[j].size())
{
if(pre&&find(in[j])!=find(in[pre]))
e.push_back((node){in[j],in[pre],j-pre});
else
pre=j;
}
sort(e.begin(),e.end());
for(register int j=0;j<e.size();++j)
if(find(e[j].u)!=find(e[j].v))
fa[find(e[j].u)]=e[j].v,ans+=2*e[j].w;
write(ans),putchar(' ');
v[s].pop_back(),v[i].pop_back();
}
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4349287/blog/4467824