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