2022NOIP A层联测31
下发文件(密码为原 accoders 比赛密码)
不稳定的道路
就是把普通的 dijkstra 稍微修改一下.
一看到这个 ,又因为总共的 dis 值是 t,所以自然就能拆成 .
这是个基本不等式,最终答案会在 处取得. 如果当前的 t 已经比它大,就取当前的 t 这个位置.
我才发现我打了这么多年来的 dijkstra 居然是假的!
原因在这里:if(fl[t]) continue; fl[t]=1;
我没有定义是否访问过!吃一堑长一智
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 200001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
struct node { ll to,c,d; };
ll n,m,dis[maxn];
vector<node> g[maxn];
priority_queue<pll,vector<pll>,greater<pll> > q;
bool fl[maxn];
inline void dij(rll x)
{
memset(dis,0x3f,sizeof(dis)); q.push((pll) { dis[x]=0,x });
while(!q.empty())
{
rll t=q.top().second;q.pop();
if(fl[t]) continue; fl[t]=1;
for(rll i=0;i<g[t].size();i++)
{
rll to=g[t][i].to,d,sq=__builtin_sqrtl(g[t][i].d);
if(sq<=dis[t]) d=dis[t]+g[t][i].c+g[t][i].d/(dis[t]+1); else d=g[t][i].c+min(g[t][i].d/sq+sq-1,g[t][i].d/(sq+1)+sq);
if(dis[to]>d) q.push((pll) { dis[to]=d,to });
}
}
}
int main()
{
freopen("road.in","r",stdin); freopen("road.out","w",stdout);
n=read();m=read();// if(n==50002&&m==99999) { puts("1999950002");return 0; }
for(rll i=1,u,v,c,d;i<=m;i++) u=read(),v=read(),c=read(),d=read(),g[u].push_back((node) { v,c,d }),g[v].push_back((node) { u,c,d });
dij(1); if(dis[n]==0x3f3f3f3f3f3f3f3f) puts("-1"); else write(dis[n]);
return 0;
}
翻转有向图
一看题目里都说了强连通分量,肯定就不会让你去打 tarjan.
一共就是四种情况:
设当前边是 u → v,有:
-
如果有一条其他从 u 到 v 的路径,且有一条从 v 到 u 的路径,那么无影响;
-
如果没有一条其他从 u 到 v 的路径,且有一条从 v 到 u 的路径,那么有影响(会减少);
-
如果有一条其他从 u 到 v 的路径,且没有一条从 v 到 u 的路径,那么有影响(会增加);
-
如果没有一条其他从 u 到 v 的路径,且没有一条从 v 到 u 的路径,那么无影响.
那么考虑怎么去求. 直接爆搜肯定是不行的,比暴力跑 tarjan 都慢.
发现这四种情况可以转化为两类方案:是否存在反向路径、当前的边是否为必须经过的边(就是是否有其他边).
这东西还是怎么去得到,可以联想二分图的知识:染色法. 染够一个就跳. 因此维护两个数组即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 1001
#define maxm 200001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,m,u[maxm],v[maxm],a[maxn][maxn],b[maxn][maxn],ans;
vector<ll> g[maxn];
inline void dfs(rll x,rll st,rll* c)
{
if(c[x]) return; c[x]=st;
for(rll i=0;i<g[x].size();i++) { rll to=g[x][i]; dfs(to,st,c); }
}
int main()
{
freopen("turn.in","r",stdin); freopen("turn.out","w",stdout);
// freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);
n=read();m=read(); for(rll i=1;i<=m;i++) u[i]=read(),v[i]=read(),g[u[i]].emplace_back(v[i]);
for(rll i=1;i<=n;i++)
{
a[i][i]=b[i][i]=1; for(rll j=0;j<g[i].size();j++) dfs(g[i][j],g[i][j],a[i]);
reverse(g[i].begin(),g[i].end()); for(rll j=0;j<g[i].size();j++) dfs(g[i][j],g[i][j],b[i]);
}
for(rll i=1;i<=m;i++) puts(((bool)(a[u[i]][v[i]]^b[u[i]][v[i]])^(bool)a[v[i]][u[i]])?"diff":"same");
return 0;
}
在表格里造序列
不会杜教筛,也不想学,打了个暴力溜了……
zzzyyds
由于是等概率的,因此用组合数直接转移没有问题,只计算总的数量,就不需要去单独考虑每个情况了.
设 dp[i][j] 为当前分成了 i 个段(连续的),当前剩下 j 个空位,期望还需要几次才能把数列填满.
转移分以下 5 种:
(无耻放图)
解释一下为什么放到长度为 2 的方案数要乘 2:显然 因为两个位置可以放在左边也可以放右边,然后另一个夹着的自动就补齐了;而 3 个的只能放中间,否则无法自动补齐.
统计答案的时候就按照期望的线性性,直接累加从 k + 1 到 n - 1 的 dp 值即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 2001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar(); while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10|'0'); }
ll n,k,t,ans,jc[maxn],ny[maxn],dp[maxn][maxn];
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
inline ll C(rll n,rll m) { if(!~(n&m)) return 1; if(n<m) return 0; return jc[n]*ny[m]%mod*ny[n-m]%mod; }
int main()
{
freopen("holiday.in","r",stdin); freopen("holiday.out","w",stdout);
jc[0]=1; for(rll i=1;i<maxn;i++) jc[i]=jc[i-1]*i%mod; ny[maxn-1]=ksm(jc[maxn-1],mod-2); for(rll i=maxn-2;~i;i--) ny[i]=ny[i+1]*(i+1)%mod;
n=read();k=read();t=read(); dp[n-1][1]=1;
for(rll i=n-1,sum,t,ny;i;i--) for(rll j=1;j<=n;j++) if(i>j&&j&&C(i-j-1,j-1)&&dp[i][j])
{
sum=i*C(i-j-1,j-1)%mod;ny=dp[i][j]*ksm(sum,mod-2)%mod;// cout<<sum<<' '<<ny<<endl;
t=(j<<1)*C(i-2-(j-1)-1,j-1-1)%mod; if(i>=2) (dp[i-2][j-1]+=t*ny%mod)%=mod;sum-=t;// cout<<t<<' ';
t=j*C(i-3-(j-1)-1,j-1-1)%mod; if(i>=3) (dp[i-3][j-1]+=t*ny%mod)%=mod;sum-=t;
// cout<<j<<' '<<i-3-(j-1)-1<<' '<<j-1-1<<' '<<C(i-3-(j-1)-1,j-1-1)<<' '<<t<<endl;
(dp[i-1][j]+=(t=(j<<1)*C(i-1-j-1,j-1)%mod)*ny%mod)%=mod;sum-=t;// cout<<t<<' ';
t=(j<<1)*C(i-2-j-1,j-1)%mod; if(i>=2) (dp[i-2][j]+=t*ny%mod)%=mod;sum-=t;// cout<<t<<endl;
sum=(sum%mod+mod)%mod;
(dp[i-1][j+1]+=sum*ny%mod)%=mod;// ,cout<<sum<<'*'<<ny<<' '<<dp[2][2]<<endl;
// cout<<i<<' '<<j<<' '<<dp[i][j]<<endl;
}
for(rll i=n-1;i>=k+1;i--) for(rll j=1;j<=n;j++) (ans+=dp[i][j]*n%mod*ksm(i,mod-2)%mod*ksm(n-i,t)%mod)%=mod;// ,cout<<i<<' '<<j<<' '<<dp[i][j]<<endl;
write(ans);
return 0;
}
为 梦 想 而 战 !
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16906666.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!