省选模拟辞旧迎新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相等的儿子里
发现这样同一个连通块内的操作一定可以维护
没调出来
总结:其实类似于树剖 一个线段树上的区间未必有实际含义 但是当其有具体含义时可以完成维护处理