总之就是 | ZROI NOIP21冲刺 Day12
「启」
A 又挂了……连着多少次挂 A 了……
C 场上没过样例放大弃,结果还嘲弄我一样的给了我 \(5\) 分……
为什么呢?
わかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんないわかんない!
缺省源使用「V5」.
「A」不知道高到哪里去了
哈哈,哈哈,哈哈,哈哈,わかんない
「A」题目简述
你想知道你的速度要多高才不至于遇到杀手。
你们所在的环境可以看成一个 \(n(2 \le 10^4)\) 个点、\(m(1 \le m \le 5 \times 10^5)\) 条边的带权无向图。你一开始位于 \(C\) 点,杀手一开始位于 \(I\) 点,而你要到 \(T\) 点去。无论杀手怎么走,你都要保证在走到 \(T\) 之前不会遇到杀手(不管是在点上遇到还是在边上遇到)。
注意:图中可以有重边和自环。
你要求出最小的非负数 \(X\),表示你的最大速度是杀手最大速度的 \(X\) 倍,在这个速度下你可以在不遇到杀手的情况下走到 \(T\)。
如果无论如何都不能在不遇到杀手的情况下走到 \(T\),请输出 \(−1.\)
「A」思路简述
先用 dij
跑出来杀手到每个点的最短路,然后二分去跑 BFS
.
但是卡了好长时间🤮
「A」Code
CI NXX(10001),MXX(500001);
const long double ESP(1e-5);
int n,m,myst,killst,goal;
double ans;
struct Node
{
int nex,to;int val;
}
r[MXX<<1];int cnt,head[NXX];
I void Add(int x,int y,int z)
{
r[++cnt]=(Node){head[x],y,z};head[x]=cnt;
r[++cnt]=(Node){head[y],x,z};head[y]=cnt;
}
struct Rode
{
int dis,id;
I bool operator < (const Rode &x) const {Heriko x.dis<dis;}
};
int dis1[NXX],dis2[NXX];bitset<NXX> vis;
I void Dijkstra(int s)
{
vis=0;mst(dis1,0x3f);priority_queue<Rode> q;
dis1[s]=0;q.push((Rode){0,s});
while(q.size())
{
int x(q.top().id);q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i(head[x]);i;i=r[i].nex)
{
int y(r[i].to);
if(dis1[y]>dis1[x]+r[i].val)
{
dis1[y]=dis1[x]+r[i].val;
if(!vis[y]) q.push((Rode){dis1[y],y});
}
}
}
}
I bool BFS(int s,double nw)
{
if(myst==killst or goal==killst) Heriko Deltana;
if(s==goal) Heriko Romanno;
vis=0;mst(dis2,0x3f);priority_queue<Rode> q;
dis2[s]=0;q.push((Rode){0,s});
while(q.size())
{
int x(q.top().id);q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i(head[x]);i;i=r[i].nex)
{
int y(r[i].to);
if(y!=killst and dis2[y]>dis2[x]+r[i].val and (1.0*dis1[y]*nw)>(1.0*(dis2[x]+r[i].val)))
{
dis2[y]=dis2[x]+r[i].val;
if(y==goal) Heriko Romanno;
q.push((Rode){dis2[y],y});
}
}
}
Heriko Deltana;
}
bool flg;
I void BinrySearch()
{
double l(0.0),r(1e5),mid;
while(l+ESP<=r)
{
mid=(l+r)/2;
if(BFS(myst,mid)) r=mid,ans=mid,flg=1;
else l=mid;
}
}
S main()
{
Files();
fr(n),fr(m);
for(int i(1),x,y,z;i<=m;++i) fr(x),fr(y),fr(z),Add(x,y,z);
fr(myst),fr(killst),fr(goal);
Dijkstra(killst);BinrySearch();
if(!flg) puts("-1");
else printf("%.6lf",ans);
Heriko Deltana;
}
「B」身经百战
好像是场上最简单的题?わかんない,わかんない
「B」题目简述
身经百战的你要和怪物战斗。有 \(n\)个怪,每个怪的血量都是一个非负整数,当血量变为负数后怪就死了。
有 \(m\) 种魔法,第 \(i\) 种用一个三元组 \((a_i,b_i,c_i)\) 表示。
你有两种操作可以做:
花费 \(1\) 点能量,给一个怪的血量减掉 \(1.\)
如果一个怪的血量是 \(a_i\),你可以花费 \(c_i\) 的能量把它的血量变为 \(b_i\)。
你希望削弱这些怪,但你不想杀生。请问最少要花费多少能量才能把所有怪的血量都变成 \(1\)。
注意:一个血量为 \(0\) 的怪仍然是存活的。
「B」思路简述
用魔法来建图,先把 \(a,b\) 中出现的点进行排序(需要去重),然后让相邻的点之间连边,边权为差,然后跑最短路。
「B」Code
CI MXX(1e5+1),NXX(1e6+1);
int n,m;
struct Node
{
int nex,to;LL val;
}
r[MXX<<1];int cnt,head[NXX];
I void Add(int x,int y,int z) {r[++cnt]=(Node){head[x],y,z};head[x]=cnt;}
struct Rode
{
LL dis;int id;
I bool operator < (const Rode &x) const {Heriko x.dis<dis;}
};
int dis[NXX];bitset<NXX> vis;
I void Dijkstra(int s)
{
vis=0;mst(dis,0x3f);priority_queue<Rode> q;
dis[s]=0;q.push((Rode){0,s});
while(q.size())
{
int x(q.top().id);q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i(head[x]);i;i=r[i].nex)
{
int y(r[i].to);
if(dis[y]>dis[x]+r[i].val)
{
dis[y]=dis[x]+r[i].val;
if(!vis[y]) q.push((Rode){dis[y],y});
}
}
}
}
int a[NXX],lena;
LL val[NXX];
struct Magic
{
int x,y,c;
}
co[MXX];
S main()
{
Files();
fr(n),fr(m);a[++lena]=1;
for(int i(1);i<=n;++i) fr(val[i]);
for(int i(1);i<=m;++i)
{
fr(co[i].x),fr(co[i].y),fr(co[i].c);
a[++lena]=co[i].x;a[++lena]=co[i].y;
}
sort(a+1,a+1+lena);
lena=unique(a+1,a+1+lena)-a-1;
for(int i(1);i<=lena;++i) Add(i,i+1,a[i+1]-a[i]);
for(int i(1);i<=m;++i)
{
co[i].x=lower_bound(a+1,a+1+lena,co[i].x)-a;
co[i].y=lower_bound(a+1,a+1+lena,co[i].y)-a;
Add(co[i].y,co[i].x,co[i].c);
}
if(!a[1]) Dijkstra(2);
else Dijkstra(1);
LL ans(0);
for(int i(1);i<=n;++i)
{
int x(upper_bound(a+1,a+1+lena,val[i])-a-1);
ans+=dis[x]+val[i]-a[x];
}
fw(ans,1);
Heriko Deltana;
}
「C」跑得比谁都快
ε=ε=ε=ε=ε=ε=ε=ε=ε=┏┏(^O^)┛┛跑的比谁都快!!!!!!!!!!!!!!!!
「C」题目简述
路上有 \(n\) 个红绿灯,把路分成了 \(n+1\) 个部分。
红绿灯的颜色是循环的,一次循环内,在 \([0,g)\)的时间里它是绿色的,在 \([g,g+r)\) 的时间里它是红色的。一开始,每个红绿灯都处于循环的开始,也就是说都会先绿 \(g\) 的时间。
有 \(q\) 次询问,给出出发时间,求要经过多长时间才能走完整条路,询问强制在线。
「C」思路简述
因为红绿的时间是可以预处理的,然后对于每个起始时间可以 \(\log n\) 的求它出发遇到的第一个红灯,然后以模上 \((g+r)\) 后的时间为下标,以第 \(i\) 个红绿灯的 \(i\) 为值存进权值线段树,维护区间最小值(
然后乆可以用同样的方法一边动态插入一边查找第 \(i\) 个红绿灯变为绿灯时从这个地方出发到终点的所需时间 \(f(i).\)
「C」Code
template<typename J>
I J Hmin(const J &x,const J &y) {Heriko x<y?x:y;}
CI MXX(1e6+5),INF(0x7fffffff),MOD(2147483647);
LL n,a[MXX],q,sum[MXX],m,co[MXX],f[MXX],lst;
struct Node
{
int lc,rc,val;
}
t[MXX<<2];int cnt,rt;
void Insert(int &x,int l,int r,int pos,int val)
{
if(!x) x=++cnt;
t[x].val=val;
if(l==r) Heriko;
int mid((l+r)>>1);
if(pos<=mid) Insert(lc(x),l,mid,pos,val);
else Insert(rc(x),mid+1,r,pos,val);
}
int Query(int x,int l,int r,int lx,int rx)
{
if(!x) Heriko n+1;
if(lx<=l and r<=rx) Heriko t[x].val;
int mid((l+r)>>1),res(INF);
if(lx<=mid) res=Hmin(res,Query(lc(x),l,mid,lx,rx));
if(rx>mid) res=Hmin(res,Query(rc(x),mid+1,r,lx,rx));
Heriko res;
}
LL Dist(int x,int y) {Heriko (y==n+1)?(sum[y]-sum[x]):(sum[y]-sum[x]+m-1)/m*m;}
LL g,r;
S main()
{
Files();
fr(n),fr(g),fr(r);m=g+r;
for(int i(1);i<=n+1;++i) fr(a[i]);
for(int i(1);i<=n+1;++i) sum[i]=sum[i-1]+a[i],co[i]=sum[i]%m;
for(int i(n);i;--i)
{
int lx((co[i]+g)%m),rx((lx+r-1)%m),pos(0);
if(lx>rx) pos=Hmin(Query(rt,0,m-1,0,rx),Query(rt,0,m-1,lx,m-1));
else pos=Query(rt,0,m-1,lx,rx);
f[i]=Dist(i,pos)+f[pos];Insert(rt,0,m-1,co[i],i);
}
fr(q);
while(q--)
{
LL x;fr(x);x^=(lst%MOD);sum[0]=-x;int pos(0);
int lx((LL)(m-x%m+g)%m),rx((lx+r-1)%m);
if(lx>rx) pos=Hmin(Query(rt,0,m-1,0,rx),Query(rt,0,m-1,lx,m-1));
else pos=Query(rt,0,m-1,lx,rx);
lst=Dist(0,pos)+f[pos];
fw(lst,1);
}
Heriko Deltana;
}
「D」人生经验
您好谢谢您出 DP 套 DP 我摆烂了对不起您哈哈。
「D」题目简述
人生经验以 \(01\) 字符串的形式存在。
一个长度为奇数的 \(01\) 字符串是好的,当且仅当它可以被用下面的办法转化为 \(1\):
-
选一个奇数 \(i(3≤i≤|S|);\)
-
把 \(S\) 分成两个字符串 A,BA,B 满足 \(|A|=i,|B|=|S|−i,S=AB;\)
-
通过一个给定的函数 \(f(U)\) 将 \(A\) 的末尾三位数变为一位数,一直重复直到 \(A\) 只剩下一个数;
-
用 \(A+B\) 替代 \(S\)。
现在给定一个字符串,包含 0
、1
、?
三种字符,?
可以替换为 0
或 1
,请问有多少种替换方案使得替换的结果是一个好串。
「D」思路简述
您好谢谢您出 DP 套 DP 我摆烂了对不起您哈哈所以我啥都不会只能说一点点以为我啥都不知道不会做这个东西哈哈わからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないは知っているはを知らない知らない知らない知らない知らない知らない知らない知らない知らないしていないかわからない知っています私は私が私が私が私が私が私が私が私を知らない知らない知らない知らない知らない知らない知らない知らない知らない知りませんわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわからないわないわからないわからないわからないわからないわからないわからないわからないわからないDPセットのやり方がわからない!
考虑分析一个串如何合法,可以发现操作都可以转化为下面的两个栈相关的操作:
-
把两个字符压入栈。
-
把一个字符压入栈,然后进行缩字符串,再让另一个字符入栈。
虽然这样会造就很多的情况,但是我们只关系我们需要的状态:
-
加入 \(1\) 后能缩成 \(0.\)
-
加入 \(1\) 后能缩成 \(1.\)
-
加入 \(0\) 后能缩成 \(1.\)
-
加入 \(0\) 后能缩成 \(0.\)
然后考虑设计 DP 状态,但是我完全蒙蔽,于是搬了 Dfkuaid 的 DP 状态:
\(f(i,a)\) 表示考虑前 \(i\) 个字符,第 \(a\) 个放法是否合法,然后考察整个字符串的话,只需要看 \(f(n−1)\) 即可。
接下来我们考虑计数,通过上面的启发,再加上字符串是不确定的,所以我们设状态 \(g(a,b,c,d)\) 分别表示上面 \(4\) 种转移是否合法,\(f(i,S)\) 表示考虑> 到第 \(i\) 位,合法转移为 \(S\) 的情况的数量。
我们每次考虑两个数,先考虑两个字符压入栈的情况,然后枚举合法情况,转移即可。
谢谢我是真的不会 DP,更别说 DP 套 DP /cy.
「D」Code
CI MXX(1e5+1),MOD(1e9+7),INF(0x3f3f3f3f);
int n,f[MXX][16],a[MXX],ans;
char s[MXX],g[MXX];
I int Get(int x,int y,int z) {Heriko g[x|(y<<1)|(z<<2)]-'0';}
I int Mod(int x,int y) {Heriko x+y>=MOD?x-MOD+y:x+y;}
I void FUCK_YOU_DP_I_CANNOT_SOLVE_DP_PROBLEMS()
{
scanf("%s%s",g,s+1);n=strlen(s+1);
mst(f,0);ans=0;f[0][9]=1;
for(int i(2);i<n;++i)
for(a[i-1]=0;a[i-1]<2;++a[i-1])
for(a[i]=0;a[i]<2;++a[i])
{
if(s[i-1]!='?' and s[i-1]!=a[i-1]+'0') continue;
if(s[i]!='?' and s[i]!=a[i]+'0') continue;
for(int s(0);s<16;++s)
{
if(!f[i-2][s]) continue;
int ss(0);
for(int p1(0);p1<2;++p1)
for(int p2(0);p2<2;++p2)
{
int p((s&(1<<((Get(a[i-1],a[i],p1)<<1)+p2)))>0);
if(Get(0,a[i],p1)==p2) p|=((s&(1<<(a[i-1]<<1)))>0);
if(Get(1,a[i],p1)==p2) p|=((s&(1<<((a[i-1]<<1)+1)))>0);
if(p) ss|=(1<<((p1<<1)+p2));
}
f[i][ss]=Mod(f[i][ss],f[i-2][s]);
}
}
for(a[n]=0;a[n]<2;++a[n])
{
if(s[n]!='?' and s[n]!=a[n]+'0') continue;
for(int s(0);s<16;++s)
if(s&(1<<((a[n]<<1)+1)))
ans=Mod(ans,f[n-1][s]);
}
fw(ans,1);
}
S main()
{
Files();
int T;fr(T);
while(T--) FUCK_YOU_DP_I_CANNOT_SOLVE_DP_PROBLEMS();
Heriko Deltana;
}
「终」
久违的补完了一套题。