CSP 模拟 5

T1 简单的序列(sequence)

原题 CF1675B Make It Increasing
不考虑负数,直接做。

点击查看代码
#include<bits/stdc++.h>
#define int long long
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=35;
int a[N],n;
signed main(){
	// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
	int T=read();
    a[0]=-2e10;
	while(T--){
		n=read();
		bool pd=0;
		for(int i=1;i<=n;++i){
			a[i]=read();
            if(a[i-1]>=0&&a[i]<=0){pd=1;}
		}
		int ans=0;
        if(!pd){
            int pos=0;
            for(int i=n;i;--i){if(a[i]<0){pos=i;break;}}
            for(int i=n-1;i>pos&&!pd;--i){
                while(a[i]>=a[i+1]){
                    if(!a[i]){pd=1;break;}
                    ans++;
                    a[i]/=2;
                }
            }
            for(int i=2;i<=pos&&!pd;++i){
                while(a[i]<=a[i-1]){
                    if(a[i]==-1){pd=1;break;}
                    ans++;
                    a[i]=std::floor(a[i]*1.0/2);
                }
            }
        }
		std::cout<<(pd?-1:ans)<<'\n';
	}	
}

T2 简单的字符串(string)

原题 [AGC016A] Shrinking
枚举答案的字母,然后每次找后面离他最近的答案字母就行。赛时读不懂题直接没做。

点击查看代码
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=1e4+10;
char s[N];
signed main(){
	// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
	std::cin>>s+1;
	int n=strlen(s+1);
	int res=1e9;;
	for(int k=0;k<=25;++k){
		int ans=0;
		int last=0;
		for(int j=n;j;--j){
			if(s[j]-'a'==k){
				last=j;continue;
			}
			if(!last){ans++;}
			else {ans=std::max(ans,last-j);}
		}
		res=std::min(res,ans);
	}
	std::cout<<res<<'\n';
}

T3 简单的博弈(tree)

原题 [AGC017D] Game on Tree
SG 函数板子,我不会,
gtm1514:

sg 函数基础应用。不会 sg 的函数的自学。
\(x\) 子树内博弈的 sg 函数是 \(f_x\)。考虑计算。
首先叶子的 sg 值显然是 \(0\)。对于每个儿子 \(v\),考虑他有什么后继状态。
单独考虑 \(v\) 子树内的博弈,sg 值是 \(f_v\)。但是由于 \(u,v\) 见有边,我们随时可以割掉这一条边,即 \(v\) 子树游戏中的每个状态都可以直接通向 \(sg=0\) 的后继状态。那么每个点的 sg 值都要加 \(1\),也就是 \(v\) 子树的 sg 值是 \(f_v+1\)。所有异或起来就是 \(f_u\)。后略。
部分分在提示 nim 游戏。菊花是白送的。


点击查看代码
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=2e5+10,MN=23;
int n,deg[N],size[N],f[1<<MN],fa[N];
std::vector<int> e[N];
inline void dfs(int u,int fa){
    f[u]=0;
    for(int v:e[u])if(v!=fa)dfs(v,u),f[u]^=f[v];
    if(u!=1)f[u]++;
}
signed main(){
	// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    n=read();
    f[1]=0;
    for(int i=2;i<=n;++i){
        int u=read(),v=read();
        e[u].push_back(v);e[v].push_back(u);
    }
    dfs(1,0);
    std::cout<<(f[1]?"Alice":"Bob")<<'\n';
}

T4 困难的图论(graph)

原题 【UER #9】知识网络
首先暴力是好想的,建完虚点直接最短路即可。
点到虚点边权为 \(0\),虚点到点边权为 \(1\),枚举每个虚点为起点跑最短路,然后跑出来的距离与实际最多只会相差 \(1\),差在了是否经过虚点,根据跑出的最短路建出最短路 DAG,当一个虚点内的点是这个点的前驱时,它没有经过虚点,知道这个之后就好做了。
但是 DAG 上统计前驱一直是一个经典不可做问题,然后这题是暴力上 bitset,然后不能用 stl,要手写,并且卡空间,所以每 \(64\) 位再分个块跑多次 topo 来统计。

点击查看代码


#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define int ull
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=510005;
int n,m,k,so[N],head[N],tot,dis[N],ans[N];
bool vis[N];
std::vector<int> p[N];
struct EDGE{int v,next,w;}e[N<<2];
struct DAG{
    int in[N],f[N],de[N];
    std::vector<int> e[N];
    inline void add(int u,int v){e[u].push_back(v);}
    inline void clear(){for(int i=1;i<=n+k;++i)e[i].clear(),in[i]=0;}
    inline void topo(){
        std::queue<int> q;
        for(int i=1;i<=n+k;++i){
            if(!in[i])q.push(i);
            de[i]=in[i];
        }
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int v:e[u]){
                f[v]|=f[u];
                de[v]--;
                if(!de[v])q.push(v);
            }
        }
    }
}G;
inline void add(int u,int v,int w){e[++tot]={v,head[u],w};head[u]=tot;}
inline void work(int s){
    for(int i=1;i<=n+k;++i)vis[i]=0,dis[i]=INT_MAX/2;
    std::deque<int> q;
    for(int j:p[s])q.push_front(j),dis[j]=0;
    while(!q.empty()){
        int u=q.front();q.pop_front();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=head[u];i;i=e[i].next){
            int w=e[i].w,v=e[i].v;
            if(vis[v])continue;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                if(w==1)q.push_back(v);
                else q.push_front(v);
            }
        }
    }
    G.clear();
    for(int u=1;u<=n+k;++u)
        for(int i=head[u];i;i=e[i].next)
            if(dis[e[i].v]==dis[u]+e[i].w)
                G.add(u,e[i].v),G.in[e[i].v]++;
    int m=p[s].size();
    for(int l=0,r;l<m;l=r+1){
        r=std::min(l+63,m-1);
        for(int j=1;j<=n+k;++j)G.f[j]=0;
        for(int j=l;j<=r;++j)G.f[p[s][j]]|=1ull<<(j-l);
        G.topo();
        for(int j=1;j<=n;++j){
            int d=dis[j];
            if(d<INT_MAX/2){
                ans[d]+=__builtin_popcountll(G.f[j]);
                ans[d+1]+=(r-l+1)-__builtin_popcountll(G.f[j]);
            }else{
                ans[2*k]+=(r-l+1);
            }
        }    
    }
}
signed main(){
    // freopen("in.in","r",stdin);freopen("out.out","w",stdout);
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;++i){
        so[i]=read()+n;add(i,so[i],0);add(so[i],i,1);p[so[i]].push_back(i);
    }for(int i=1;i<=m;++i){
        int u=read(),v=read();add(u,v,1);add(v,u,1);
    }for(int i=1;i<=k;++i){
        work(i+n);
    }
    std::cout<<0<<' ';
    for(int i=1;i<=2*k;++i)std::cout<<ans[i]/2<<' ';std::cout<<'\n';
}


点击查看

T1

小细节题。
注意正负

T2

没看懂题目

T3

只会 20 状压和特殊性质

T4

建完虚点后不再考虑同类。
路径长度很短,所以可以直接往外搜 \(k\) 层,这样是 \(n^2\) 的。记忆化?记一下 \(f_{i,k}\) 表示从 \(i\) 向外搜 \(k\) 层的节点数。
对于一个 \(i\) 能够正确处理出 \(f_{i,k}\)

posted @ 2024-07-25 14:57  Ishar-zdl  阅读(42)  评论(0)    收藏  举报