Loading

省选模拟辞旧迎新3-5

省选模拟之辞旧迎新5

交通

发现到了相同路口后的行动一样 所以求出在每个路口从 $ 0 $ 时刻出发到学校所需时间即可 从n往前倒推

可以在模意义下查询对应的红灯时间段内的往后最小编号 线段树即可

总结:想到了做法没想到怎么维护 没有应用好“模意义下”这个东西

code
#include <iostream>
#define Sakura int
#define Re register ll
#define _ putchar(' ')
#define el putchar('\n')
#define ll long long
#define fre(x,y) freopen(#x".in","r",stdin),freopen(#y".out","w",stdout);

using namespace std;

const ll maxn=5e4+10;
const ll Maxn=maxn*80;

inline ll read(){
    ll x=0,f=0;char c=getchar();
    while(!isdigit(c)) f|=c=='-',c=getchar();
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return f?-x:x;
}

inline void ot(ll x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) ot(x/10);putchar(x%10|48);
}

ll n,g,r,T,m;
ll a[maxn],s[maxn];
ll f[maxn];

struct Seg {
	ll rt,tot,Min[Maxn],lc[Maxn],rc[Maxn];

	inline void pushup(ll p) {
		Min[p]=n+1;
		if(lc[p]) Min[p]=min(Min[p],Min[lc[p]]);
		if(rc[p]) Min[p]=min(Min[p],Min[rc[p]]);
	}

	void upd(ll &p,ll l,ll r,ll pos,ll x) {
		if(!p) p=++tot;
		if(l==r) return Min[p]=x,void();
		ll mid=l+r>>1;
		pos<=mid?upd(lc[p],l,mid,pos,x):upd(rc[p],mid+1,r,pos,x);
		pushup(p);
	}

	ll qry(ll p,ll l,ll r,ll L,ll R) {
		if(L>R) return n+1;
		if(!p) return n+1;
		if(L<=l&&r<=R) return Min[p];
		ll mid=l+r>>1;
		ll res=n+1;
		if(L<=mid) res=min(res,qry(lc[p],l,mid,L,R));
		if(mid<R) res=min(res,qry(rc[p],mid+1,r,L,R));
		return res;
	}
}tree;

inline ll get_nxt(ll pos) {
	int L=(pos+g)%T,R=(pos+g+r-1)%T;
	if(L<=R) return tree.qry(tree.rt,0,T-1,L,R);
	return min(tree.qry(tree.rt,0,T-1,L,T-1),tree.qry(tree.rt,0,T-1,0,R));
}

Sakura main() {
	fre(traffic,traffic);
	n=read(),g=read(),r=read(),T=g+r;
	for(Re i=1;i<=n+1;++i) a[i]=read();
	for(Re i=1;i<=n+1;++i) s[i]=s[i-1]+a[i];
	for(Re i=n;i>=1;--i) {
		ll j=get_nxt(s[i]%T);
		// ot(j),el;
		f[i]=f[j]+s[j]-s[i];
		if(j!=n+1) f[i]+=T-(s[j]-s[i])%T;
		tree.upd(tree.rt,0,T-1,s[i]%T,i);
	}
	m=read();
	for(Re i=1;i<=m;++i) {
		ll t=read();
		ll j=get_nxt(T-t%T);
		// _,ot(j),el;
		ll res=f[j]+s[j]+t;
		if(j!=n+1) res+=T-(s[j]+t)%T;
		ot(res),el;
	}
}

选拔

诈骗题

bitset优化 $ n^2 $ dp 把所有串加上分隔符变成一个串 用左右移支持转移 用与操作支持合并

总结:bitset优化dp

code
#include <iostream>
#include <vector>
#include <bitset>
#include <cstring>
#define Sakura int
#define Re register int
#define _ putchar(' ')
#define el putchar('\n')
#define fst first
#define scd second
#define fre(x,y) freopen(#x".in","r",stdin),freopen(#y".out","w",stdout);

using namespace std;

const int maxn=3e4+10;

inline int read(){
    int x=0,f=0;char c=getchar();
    while(!isdigit(c)) f|=c=='-',c=getchar();
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return f?-x:x;
}

inline void ot(int x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) ot(x/10);putchar(x%10|48);
}

bitset<maxn<<1> f[maxn],g[maxn],ans,bit[27];
vector<pair<int,int> > G[maxn];
int n,m;
int fa[maxn],dfn[maxn],tim;
string s,t[maxn];

inline void add(int x,int y,int z) {
    G[x].emplace_back(y,z);
}

void dfs(int u) {
    dfn[++tim]=u;
    for(auto e:G[u]) {
        int v=e.fst;
        if(v!=fa[u]) {
            fa[v]=u;
            dfs(v);
        }
    }
}

Sakura main() {
    fre(selection,selection);
    n=read();
    for(Re i=1;i<n;++i) {
        int x=read(),y=read(),c=getchar()-'a';
        add(x,y,c);
        add(y,x,c);
    }
    m=read();
    for(Re i=1;i<=m;++i) {
        cin>>t[i];
        s=s+char('z'+1)+t[i];
    }
    s=s+char('z'+1);
    // cout<<s<<endl;
    // cout<<s.length()<<endl;
    for(Re i=s.length()-1;i>=0;--i) bit[s[i]-'a'][i]=true;//,ot(s[i]-'a'),_,ot(i),_,ot(bit[s[i]-'a'][i]),el;
    // for(Re i=0;i<=26;++i) {
    //     for(Re j=0;j<s.length();++j)
    //         ot(bit[i][j]);
    //     el;
    //     cout<<bit[i]<<endl;
    // }
    dfs(1);
    // for(Re i=0;i<s.length();++i) ot(ans[i]);el;
    for(Re i=n;i>=1;--i) {
        int u=dfn[i];
        f[u]=g[u]=bit[26];
        for(auto e:G[u]) {
            int v=e.fst;
            if(v!=fa[u]) {
                int c=e.scd;
                f[v]=(f[v]<<1)&bit[c];
                g[v]=(g[v]>>1)&bit[c];
                ans|=((f[u]<<1)&g[v]);
                ans|=(g[u]&(f[v]<<1));
                f[u]|=f[v],g[u]|=g[v];
            }
        }
    }
    int len=1;
    for(Re i=1;i<=m;++i) {
        int tlen=t[i].size();
        bool flag=false;
        for(Re j=0;j<=tlen;++j) 
            if(ans[len+j]) {
                flag=true;
                break;
            }
        puts(flag?"YES":"NO");
        len+=tlen+1;
    }
}

省选模拟之辞旧迎新4

序列划分

考虑线段树求每个区间 $ mex $ 时 如果从后往前求 求得的区间左端点是固定的

观察dp式子: $ f[i] = \sum_{j=0}^{i-1} f[j+1] \times mex(j+1,i) $

转化一下 从 $ j $ 往 $ i $ 贡献即可

线段树维护三个 $ tag $ 区间加 $ tag $,区间乘 $ tag $,区间覆盖 $ tag $

区间维护 $ mex $ 与dp值加和

没调出来

从后往前也可以想到CDQ

总结:改变贡献计算方式 从后往前

重排列([AGC010E]Rearranging)

相邻互质可交换:不互质的相对位置不变

把不互质的数之间连边构成一张不一定联通的图

发现先手任意排序操作等同于给边定向 把图变成 $ DAG $

后手要遍历这张图 按照出点到入点的顺序

所以贪心 $ dfs $ 从小到大给边定向 再贪心从大到小弹出最后序列即可

总结:转换思考角度 从最后结果而不是具体操作过程来考虑问题

code
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#define Sakura int
#define Re register ll
#define _ putchar(' ')
#define el putchar('\n')
#define ll long long
#define fre(x,y) freopen(#x".in","r",stdin),freopen(#y".out","w",stdout);

using namespace std;

const ll maxn=2e3+10;

inline ll read(){
    ll x=0,f=0;char c=getchar();
    while(!isdigit(c)) f|=c=='-',c=getchar();
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return f?-x:x;
}

inline void ot(ll x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) ot(x/10);putchar(x%10|48);
}

vector<int> G1[maxn],G2[maxn];
priority_queue<pair<int,int> > q;
int n;
int a[maxn];
bool vis[maxn];

void dfs(int u) {
    vis[u]=true;
    for(auto v:G1[u])
        if(!vis[v]) {
            // ot(u),_,ot(v),el;
            G2[u].emplace_back(v);
            dfs(v);
        }
}

Sakura main() {
    // fre(permutation,permutation);
    n=read();
    for(Re i=1;i<=n;++i) a[i]=read();
    sort(a+1,a+n+1);
    for(Re i=1;i<=n;++i)
        for(Re j=i+1;j<=n;++j)
            if(__gcd(a[i],a[j])!=1) {
                G1[i].emplace_back(j);
                G1[j].emplace_back(i);
            }
    for(Re i=1;i<=n;++i) 
        if(!vis[i]) {
            dfs(i);
            // ot(i),_,ot(a[i]),el;
            q.push({a[i],i});
        }
    while(!q.empty()) {
        int u=q.top().second;
        q.pop();
        ot(a[u]),_;
        for(auto v:G2[u]) q.push({a[v],v});
    }
}

省选模拟之辞旧迎新3

黑白树

用每个连通块内深度最小的点来指代每个连通块 那么该连通块内的所有的点都在其子树内

考虑同一个连通块到根路径上异色点数量一定相等

所以每个区间维护区间LCA到根每种颜色的点的数量cnt 下放标记时只下放到每种颜色对应的另一种颜色cnt相等的儿子里

发现这样同一个连通块内的操作一定可以维护

没调出来

总结:其实类似于树剖 一个线段树上的区间未必有实际含义 但是当其有具体含义时可以完成维护处理

posted @ 2023-02-03 19:45  hzoi_Sakura  阅读(24)  评论(0编辑  收藏  举报