恩偶爱皮模拟尸体-29
作者:互联网
水博客太快乐了。。。
好几场模拟赛的博客都因为懒所以被咕掉了,也不打算补,就直接从新的比赛开始水吧。。。
因为用了 \(HZ\) 的电脑,换了输入法,所以标题也和原来不一样了。。。。
考场
先大概地看了一下三道题,发现 \(T3\) 可以大力树剖线段树,于是想也不想就开始写了。。。
写了大概一个小时,发现想法是错的。。。
但是在原代码的基础上稍微改一下就可以了。。。
于是稍微改了一下。。。过了第三个大样例,然而第二个大样例挂了。。。。。
这句号好难看。。。
其实有个非常简单的情况没有考虑到。。。。
但是考场上也没看出来,就这样吧。。。
回头看 \(T1\) \(T2\) , \(T1\) 着实没什么思路,直接暴力,感觉膜数这么小有什么玄机。。。但是也没有深思。。。。
然后看 \(T2\) ,乍一看就像个同余最短路的样子。。。
这句号好难看。。。
于是大力同余最短路,然而在同余最短的的时候因为没有考虑到 \(C\) 对答案的限制,所以一定会有少考虑的情况,但因为最后时间不够了,想也没想就交了。。。。
分数
\(t1\ 20pts\ +\ t2\ 90pts\ +\ t3\ 80pts\ =\ 190pts\)
发现 \(t2\) 居然有 \(90pts\) ???
震惊,这明明就是个假算法啊喂!!!
\(t3\) 少考虑一种请款挂成了 \(80pts\) 。。。
实际上是非常简单的情况。。。然而我没有想到。。。
题解
A. 最长不下降子序列
膜数非常小,因此一定会有循环节且长度很短。。。
而在选择最长不下降子序列时,每个循环节至少会选择一个点,因此只要在至多 \(D\) 个循环节中选出最长不下降子序列,再在没有选到的每一个循环节中选则一个数即可。。
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e6+10, D=200;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int n, t0, a, b, c, d, len, ans;
int num[N], vis[N], st, ul;
int up[N], low[N];
class TRE{
private :
int a[N];
inline int lb(int x) { return x&-x; }
public :
inline void add(int p, int x) { for(; p<D; p+=lb(p)) a[p]=max(a[p], x); }
inline int query(int p) { int ans=0; for(; p; p-=lb(p)) ans=max(ans, a[p]); return ans; }
}t;
signed main(void){
n=read(); t0=read();
a=read(), b=read(), c=read(), d=read();
vis[num[1]=t0]=1;
for(int i=2; i<=n; ++i){
num[i]=(num[i-1]*num[i-1]*a+num[i-1]*b+c)%d;
if(vis[num[i]]) { len=i-vis[num[i]]; st=i-len; break; }
vis[num[i]]=i;
}
if(len) ul=(n-st+1)/len;
if(ul<=len){
t.add(t0+1, 1);
for(int i=2; i<=n; ++i){
num[i]=(num[i-1]*num[i-1]*a+num[i-1]*b+c)%d;
t.add(num[i]+1, t.query(num[i]+1)+1);
}
printf("%lld\n", t.query(max(t0+1, d))); return 0;
}
t.add(t0+1, 1);
for(int i=2; i<=len*d+st-1+((n-st+1)%len); ++i){
num[i]=(num[i-1]*num[i-1]*a+num[i-1]*b+c)%d;
t.add(num[i]+1, t.query(num[i]+1)+1);
}
printf("%lld\n", t.query(max(t0+1, d))+ul-d);
return 0;
}
B. 完全背包问题
继续考虑同余最短路。。。
若不会同余最短路,可以看一下这个完全是为了推销博客而出现的链接。。。
如果直接在u原数据上跑同余最短路,显然没有办法考虑 \(C\) 对答案的限制,因此考虑将图分层,更改原来同余最短路的定义,设 \(dis_{i,j}\) 表示用了 \(i\) 个大于等于 \(l\) 的物品,在膜 \(D\) 意义下为 \(j\) 的最小值。。。
然后直接跑分层图最短路,对于每个询问 \(O(C)\) 判断是否合法即可。。。
code
#include<bits/stdc++.h>
using namespace std;
#define ul first
#define num second
#define int long long
const int N=1e4+10, C=40;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int n, m, l, c;
int v[N], dis[N][C];
bool vis[N][C];
queue<pair<int, int> > q;
void spfa(){
memset(dis, 0x3f3f, sizeof dis);
dis[0][0]=0;
q.push(make_pair(0, 0));
while(!q.empty()){
pair<int, int > u=q.front(); q.pop(); vis[u.ul][u.num]=0;
for(int i=2; i<=n; ++i){
if(v[i]>=l&&u.num==c) break;
if(dis[(v[i]+u.ul)%v[1]][u.num+1]>dis[u.ul][u.num]+v[i]&&v[i]>=l){
dis[(v[i]+u.ul)%v[1]][u.num+1]=dis[u.ul][u.num]+v[i];
if(!vis[(v[i]+u.ul)%v[1]][u.num+1]) q.push(make_pair((v[i]+u.ul)%v[1], u.num+1)), vis[(v[i]+u.ul)%v[1]][u.num+1]=1;
}
if(v[i]<l&&dis[(v[i]+u.ul)%v[1]][u.num]>dis[u.ul][u.num]+v[i]){
dis[(v[i]+u.ul)%v[1]][u.num]=dis[u.ul][u.num]+v[i];
if(!vis[(v[i]+u.ul)%v[1]][u.num]) q.push(make_pair((v[i]+u.ul)%v[1], u.num)), vis[(v[i]+u.ul)%v[1]][u.num]=1;
}
}
}
}
signed main(void){
n=read(), m=read();
for(int i=1; i<=n; ++i) v[i]=read();
sort(v+1, v+1+n); int x, num=0;
l=read(), c=read(); spfa();
bool flag;
while(m--){
x=read(); flag=0;
for(int i=c; ~i; --i) if(x>=dis[x%v[1]][i]) { flag=1; break; }
flag ? puts("Yes") : puts("No");
num+=!flag;
}
return 0;
}
又好写跑的又快。。。
C. 最近公共祖先
直接大力树剖线段树,对于每一个修改操作,将这个点到根节点的链进行修改,每一个查询也将这个点到根节点的链进行查询。。。
一堆细节要考虑,懒得写了。。。
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10, INF=0x7fffffff;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int n, m, w[N], num2[N], to[N];
vector<int > l[N], l1[N];
int dep[N], fa[N], siz[N], top[N], son[N], num[N], num1[N], ind;
bool ul, vis[N];
char ch[20];
struct TRE{
int l, r, maxn;
bool ul;
}t[N<<2];
void built(int l, int r, int p){
t[p].l=l, t[p].r=r;
if(l==r) return;
int mid=(l+r)>>1;
built(l, mid, p<<1); built(mid+1, r, p<<1|1);
}
void change(int l, int r, int p){
if(l>r) return;
if(l<=t[p].l&&r>=t[p].r) { t[p].ul=1; return; }
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) change(l, r, p<<1);
if(r>mid) change(l, r, p<<1|1);
}
void insert(int x, int w1, int p){
if(t[p].l==t[p].r) { t[p].maxn=w1; return; }
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid) insert(x, w1, p<<1);
else insert(x, w1, p<<1|1);
t[p].maxn=max(t[p<<1].maxn, t[p<<1|1].maxn);
}
int que(int l, int r, int p){
if(l>r) return 0;
if(l<=t[p].l&&r>=t[p].r) return t[p].maxn;
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid&&r>mid) return max(que(l, r, p<<1), que(l, r, p<<1|1));
if(l<=mid) return que(l, r, p<<1);
return que(l, r, p<<1|1);
}
bool check(int x, int p){
if(t[p].ul) return 1;
if(t[p].l==t[p].r) return 0;
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid) return check(x, p<<1);
return check(x, p<<1|1);
}
void dfs1(int u, int f){
siz[u]=1, dep[u]=dep[f]+1, fa[u]=f;
for(int v : l[u]){
if(v==f) continue;
dfs1(v, u); siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u, int tp){
top[u]=tp; num[u]=++ind, num1[ind]=u;
if(son[u]) dfs2(son[u], tp);
for(int v : l[u]) if(v!=fa[u]&&v!=son[u]) dfs2(v, v);
}
inline void modify(int u){
while(u){
change(num[top[u]], num[u]-1, 1);
insert(num[u], w[u], 1);
if(to[fa[top[u]]]!=top[u]) num2[fa[top[u]]]++;
to[fa[top[u]]]=top[u];
u=fa[top[u]];
}
}
inline int query(int u){
int ans=-INF, v=0;
if(vis[u]) ans=w[u];
while(u){
ans=max(ans, que(num[top[u]], num[u]-1, 1));
if(num2[u]>1||(to[u]!=v&&num2[u])||check(num[u], 1)||vis[u]) ans=max(ans, w[u]);
v=top[u], u=fa[v];
}
return ans;
}
signed main(void){
n=read(), m=read(); int x, y;
for(int i=1; i<=n; ++i) w[i]=read();
for(int i=1; i<n; ++i){
x=read(), y=read();
l[x].push_back(y);
l[y].push_back(x);
}
dfs1(1, 0), dfs2(1, 1); built(1, n, 1);
while(m--){
scanf("%s", ch+1); x=read();
if(ch[1]=='Q'){
if(!ul) { printf("-1\n"); continue; }
printf("%d\n", query(x));
}else modify(x), ul=1, vis[x]=1;
}
return 0;
}
也可以不树剖,直接在 \(dfs\) 序上乱搞,可以少一个 \(log\) 。。。
标签:ch,int,top,29,恩偶,ul,num,dis,爱皮 来源: https://www.cnblogs.com/CTcode/p/NOIP_29.html