test20231103
T1
还算是一道简单题,通过二分可以轻松求解。(但是我因为没有判断左端点挂了 \(10pts\) ,不然我就是本场比赛的 \(rk1\) 了)
虽然题解上说单调性是错误的,但是而二分能过,那就二分水过去吧。
int n,k;
int a[2050];
bool vis[2050];
inline int work(int x){
memset(vis,0,sizeof vis);
int ans=0;
up(i,1,n){
int res=x,flg=0;
up(j,1,n){
if(vis[j])continue;
if(res>=a[j]){
res-=a[j];
vis[j]=1;
flg=1;
}
if(res==0)break;
}
if(flg)ans++;
}
return ans;
}
inline bool cmp(int x,int y){
return x>y;
}
signed main(){
n=read();k=read();
int maxl=0;
up(i,1,n){
a[i]=read();
maxl=max(maxl,a[i]);
}
sort(a+1,a+1+n,cmp);
int l=maxl,r=1e7,ans;
while(l<=r){
int mid=(l+r)>>1;
if(work(mid)<=k){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans;
return 0;
}
T2
完成成就:考场干黑(?或许)。
做题的时候还觉得没什么,考完后看一下题解,发现我怎么这么 nb,竟然搞出这道题。
这还是一道博弈论(最近怎么这么多博弈论)。
看着似乎很不好搞的样子。
先推一推结论,如果总石块数是奇数,那么先手必胜,因为可以直接取一个石块。如果总石块数是偶数,那么问题就复杂了起来,不是很会。
那么我是如何解决这道题的?
答:观察大样例,发现第一个性质,每堆石块可取的石子个数与前一次会相差 \(2^k\),第二个性质,取走石子后,所有石子的前 \(k\) 位异或和为 \(0\)。
int n,k;
int a[N];
int cnt2[N];
int tot[50],sum;
vector<int>ans[N];
inline bool check(int p,int del,int lim){
int t=a[p]-del;
up(i,0,lim){
if(tot[i]%2==0&&(((a[p]>>i)&1)!=((t>>i)&1)))return 0;
if(tot[i]%2==1&&(((a[p]>>i)&1)==((t>>i)&1)))return 0;
}
return 1;
}
signed main(){
freopen("nim.in","r",stdin);
freopen("nim.out","w",stdout);
n=read();k=read();
up(i,1,n){
a[i]=read();
sum+=a[i];
dn(j,31,0){
if((a[i]>>j)&1){
tot[j]++;
}
}
}
bool flg=0;
up(i,1,n){
int res=0;
up(j,0,31){
if(res+(1<<j)>min(k,a[i]))break;
if(check(i,res+(1ll<<j),j)){
res+=(1<<j);
flg=1;
ans[i].push_back(res);
}
}
}
if(!flg){
puts("0");
return 0;
}
puts("1");
up(i,1,n){
for(auto v:ans[i]){
write(i,0);
write(v,1);
}
}
return 0;
}
T3
一道简单题,只要想到建立失配树就出来了。
vector<int>g[N];
char s[N];
int nxt[N],n;
inline void getnxt(){
int len=strlen(s+1),j=0;
up(i,2,len){
while(j&&s[i]!=s[j+1])j=nxt[j];
if(s[j+1]==s[i])j++;
nxt[i]=j;
}
}
struct treelca{
int siz[N],son[N],fa[N],dep[N],top[N];
inline void dfs1(int u,int from){
siz[u]=1;son[u]=0;
dep[u]=dep[from]+1;
for(auto v:g[u]){
if(v==from) continue;
fa[v]=u;dfs1(v,u);
if(siz[v]>siz[son[u]])son[u]=v;
siz[u]+=siz[v];
}
}
inline void dfs2(int u,int tp){
top[u]=tp;
if(son[u]!=0)dfs2(son[u],tp);
for(auto v:g[u]){
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
inline int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
else y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
inline void failtree(){
dn(i,n,1){
siz[i]++;
if(nxt[i])siz[nxt[i]]+=siz[i];
if(siz[i]>=siz[son[nxt[i]]])son[nxt[i]]=i;
}
up(i,1,n){
dep[i]=dep[nxt[i]]+1;
if(son[nxt[i]]!=i)top[i]=i;
else top[i]=top[nxt[i]];
fa[i]=nxt[i];
}
}
}T;
bool vis[N];
int fac[N],ifac[N];
inline int ksm(int a,int b){
int res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
inline void init(){
fac[0]=1;ifac[0]=1;
up(i,1,n+10)fac[i]=fac[i-1]*i%mod;
ifac[n+10]=ksm(fac[n+10],mod-2);
dn(i,n+9,1)ifac[i]=ifac[i+1]*(i+1)%mod;
}
inline int C(int n,int m){
if(n<m)return 0;
return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int k;
int ans;
signed main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
k=read();
scanf("%s",s+1);
n=strlen(s+1);
init();
getnxt();
T.failtree();
ans=C(n+1,k);
int t=0;
up(i,1,n){
t=(t+C(T.siz[i],k)*(T.dep[i])%mod)%mod;
ans=(ans+C(T.siz[i],k))%mod;
}
cout<<(ans+t*2)%mod;
return 0;
}
T4
很古怪的一道题。
想出了结论,但是没有做出 \(60pts\) 的暴力,还是码力太低了。
因为原图有 \(n-1\) 条边,新图同样有 \(n-1\) 条边,所以每次都必须要染上颜色。
所以把地图上相邻的点都覆盖在原图上,然后寻找经过次数为 \(1\) 的边,每一次找到这样的边,那么就可以把树分成两部分,然后进行递归到子树里进行查找。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+6,M=998244353;
using ll=long long;
using ul=unsigned long long;
mt19937_64 rg(random_device{}());
ul rp[N],vl[N];
void NO(){puts("NO"),exit(0);}
void YES(){puts("YES"),exit(0);}
int n,f[N],lt[N],d[N],dfn[N],dlt;
int sz[N],lc[N],c1[N],rev[N];
int q[N],ql,qr;
vector<int>lk[N];
bitset<N>vs;
void run(ul v){
int k=lower_bound(rp+1,rp+n,v)-rp;
if(k==n||vs[k])NO();
vs[q[++qr]=k]=1;
if(qr==n-1)YES();
}
void dfs(int x){
sz[x]=1;
for(int y:lk[x]){
auto it=lk[y].begin();
while(*it!=x)++it;
lk[y].erase(it);
d[y]=d[x]+1;
f[y]=x,dfs(y),sz[x]+=sz[y];
if(sz[y]>sz[lc[x]])lc[x]=y;
}
}
void dfs2(int x){
rev[dfn[x]=++dlt]=x;
if(lc[x])lt[lc[x]]=lt[x],dfs2(lc[x]);
for(int y:lk[x])
if(y!=lc[x])lt[y]=y,dfs2(y);
}
int lca(int x,int y){
while(lt[x]!=lt[y]){
if(d[lt[x]]>d[lt[y]])x=f[lt[x]];
else y=f[lt[y]];
}return d[x]<d[y]?x:y;
}
struct Eg{int x,y;}g[N];
void dfs3(int x){
for(int y:lk[x])
dfs3(y),vl[x]^=vl[y],c1[x]+=c1[y];
}
struct ZYFPSGT{
#define ls x<<1
#define rs x<<1|1
vector<int>mn,tg;
vector<ul>vr;
int D,U;
void build(int x,int l,int r){
if(l==r)mn[x]=c1[rev[l]];
else{
int md=l+r>>1;
build(ls,l,md),build(rs,md+1,r);
mn[x]=min(mn[ls],mn[rs]);
}
}
ul mst;
void atg(int x,int t1,ul t2){
tg[x]+=t1,mn[x]-=t1,vr[x]^=t2;
}
void pd(int x){
if(tg[x]){
atg(ls,tg[x],vr[x]);
atg(rs,tg[x],vr[x]);
vr[x]=tg[x]=0;
}
}
void rec(int x,int l,int r){
if(l==r)run(vl[rev[l]]^vr[x]),mn[x]=1e9;
else{
int md=l+r>>1;pd(x);
if(mn[ls]==1)rec(ls,l,md);
if(mn[rs]==1)rec(rs,md+1,r);
mn[x]=min(mn[ls],mn[rs]);
}
}
void add(int x,int l,int r,int L,int R){
if(l>=L&&r<=R){
atg(x,1,mst);
if(mn[x]==1)rec(x,l,r);
}else{
int md=l+r>>1;pd(x);
if(L<=md)add(ls,l,md,L,R);
if(md<R)add(rs,md+1,r,L,R);
mn[x]=min(mn[ls],mn[rs]);
}
}
void init(int _l,int _r){
D=_l,U=_r;int n=(1<<__lg(U-D+3)+2)+3;
mn.resize(n),tg.resize(n),vr.resize(n);
build(1,D,U);
}
void add(int l,int r,ul v){mst=v,add(1,D,U,l,r);}
}tr[N];
void run(int x,int y,ul v){
while(lt[x]!=lt[y]){
if(d[lt[x]]<d[lt[y]])swap(x,y);
tr[lt[x]].add(dfn[lt[x]],dfn[x],v);
x=f[lt[x]];
}if(d[x]>d[y])swap(x,y);
if(x!=y)tr[lt[x]].add(dfn[x]+1,dfn[y],v);
}
int main(){
freopen("ants.in","r",stdin);
freopen("ants.out","w",stdout);
ios::sync_with_stdio(false);
int i,j,k,l,r,x,y,z;
for(i=1,cin>>n;i<n;++i){
cin>>x>>y,rp[i]=rg();
lk[x].push_back(y);
lk[y].push_back(x);
}if(n==1)YES();
dfs(1),lt[1]=ql=1,dfs2(1);
sort(rp+1,rp+n);
for(i=1;i<n;++i){
cin>>x>>y,g[i]={x,y};
vl[x]^=rp[i],vl[y]^=rp[i];
z=lca(x,y);
++c1[x],++c1[y],c1[z]-=2;
}dfs3(ql=1),c1[1]=1e9;
for(x=2;x<=n;++x)
if(!c1[x])NO();
else if(c1[x]==1)c1[x]=1e9,run(vl[x]);
for(x=1;x<=n;++x)
if(!lc[x])tr[lt[x]].init(dfn[lt[x]],dfn[x]);
while(ql<=qr){
k=q[ql++],run(g[k].x,g[k].y,rp[k]);
if(clock()>4.8*CLOCKS_PER_SEC)YES();
}NO();return 0;
}