noip模拟58
A. Lesson5!
发现如果某个点都判断是不是在最长路的话会被卡成 \(O(n^2)\).
考虑怎么维护最长路径.
线段树,我们最初先反着走一遍,找到逆着走的最长路.
然后选择一个个删除,之后回来.
发现可以覆盖到所有路径.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long int
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll res=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return cit?res:-res;
}
} using namespace BSS;
const ll N=1e5+21,inf=1e15;
ll m,n,head,tail,cnt,ansd,ansx,Ts;
ll que[N],f[N],g[N],df[N],dg[N],sf[N];
vector<ll> to[N],re[N];
multiset<ll> s;
inline void Topo_I(){
head=1,tail=0; ll u; Fill(g,-0x3f);
for(int i=1;i<=n;i++)
if(!dg[i]) que[++tail]=i,g[i]=0;
while(head<=tail){
u=que[head++];
for(auto v : re[u]){
g[v]=max(g[v],g[u]+1);
if(not(--dg[v])) que[++tail]=v;
}
}
}
inline void Topo_II(){
head=1,tail=0; ll u; Fill(f,-0x3f);
for(int i=1;i<=n;i++)
if(!df[i]) que[++tail]=i,f[i]=0;
while(head<=tail){
u=que[head++],sf[++cnt]=u;
for(auto v : to[u]){
f[v]=max(f[v],f[u]+1);
if(not(--df[v])) que[++tail]=v;
}
}
}
signed main(){
File(johnny);
Ts=read();
while(Ts--){
n=read(),m=read(),ansx=-1,ansd=inf,cnt=0; ll u,v,now;
for(int i=1;i<=m;i++){
u=read(),v=read(),dg[u]++,df[v]++;
to[u].push_back(v),re[v].push_back(u);
}
Topo_I(),Topo_II();
for(int i=1;i<=n;i++) s.insert(g[i]);
for(int i=1;i<=n;i++){
u=sf[i];
for(auto v : re[u]) s.erase(s.find(g[u]+f[v]+1));
s.erase(s.find(g[u]));
if(s.size()){
now=*--s.end();
if(now<ansd or (now==ansd and u<ansx))
ansd=now,ansx=u;
}
for(auto v : to[u]) s.insert(f[u]+g[v]+1);
s.insert(f[u]);
}
if(ansx==-1) ansx=1,ansd=0;
printf("%lld %lld\n",ansx,ansd); s.clear();
for(int i=1;i<=n;i++){
df[i]=0,dg[i]=0,sf[i]=0;
to[i].clear(),re[i].clear();
}
}
exit(0);
}
B. 贝尔数
考场上只差一个矩阵快速幂.
还是对快速幂的模型掌握的不够好.
快速幂一定是有周期性的,是有规律可寻的.
而本题中可以看出是对连续的一端区间取模.
那么一定就应该是一段周期性的序列.
每次可以选择把序列向左移动 \(P\ -\ 1\) 个格子.
于是快速幂就很可做了.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long int
#define ull unsigned ll
#define lf double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define FILE(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
int ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll mod=95041567;
ll m,n,Ts,ans;
ll md[7]={0,31,37,41,43,47};
ll f[57],bell[1007];
ll C[1007][1007],g[57][57];
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b) return x=1,y=0,a;
ll d=exgcd(b,a%b,x,y),z=x;
return x=y,y=z-y*(a/b),d;
}
inline void mul(ll now){
ll c[57]={0};
for(int i=1;i<=now;i++){
for(int j=1;j<=now;j++)
c[i]=(c[i]+f[j]*g[j][i]%now)%now;
}
Copy(f,c);
}
inline void mulself(ll now){
ll c[57][57]={0};
for(int i=1;i<=now;i++){
for(int j=1;j<=now;j++)
for(int k=1;k<=now;k++)
c[i][j]=(c[i][j]+g[i][k]*g[k][j]%now)%now;
}
Copy(g,c);
}
inline ll solve(ll x){
Fill(g,0),Fill(f,0);
ll b=n/(md[x]-1),st=n%(md[x]-1);
for(int i=1;i<=md[x];i++){
f[i]=bell[st+i-1]%md[x];
}
g[md[x]][1]=1;
for(int i=2;i<=md[x];i++) g[i-1][i]=1,g[i][i]=1;
for(;b;b>>=1,mulself(md[x])) if(b&1) mul(md[x]);
return f[1]%md[x];
}
signed main(){
FILE(bell);
bell[0]=1,bell[1]=1;
for(int i=0;i<=1000;i++){
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
for(int i=1;i<=1000;i++){
for(int j=0;j<=i;j++){
bell[i+1]=(bell[i+1]+C[i][j]*bell[j]%mod)%mod;
}
}
Ts=read(); ll res,cnt,x,y;
while(Ts--){
n=read(),ans=0; if(n<=1000){ printf("%lld\n",bell[n]); continue; }
for(int i=1;i<=5;i++){
res=solve(i),exgcd(mod/md[i],md[i],x,y);
ans=(ans+(x%md[i]+md[i])%mod*res%mod*(mod/md[i])%mod)%mod;
}
printf("%lld\n",ans%mod);
}
exit(0);
}
C. 穿越广场
考场感觉一定是个 \(dp\).
但是没有再去考虑和字符串有关的算法.