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

image

posted @ 2023-11-05 22:30  LiQXing  阅读(50)  评论(0)    收藏  举报