2021.9.21考试总结[NOIP模拟58]
T1 lesson5!
开始以为是个无向图,直接不懂,跳去T2了。
之后有看了一眼发现可暴力,于是有了\(80pts\)。
发现这个图是有拓扑序的,于是可以用拓扑排序找最长路径。先找原图内在最长路径上的点,挨个删了跑拓扑排,看哪个最短。
正解太nb了待补。
\(code:\)
80pts
#include<bits/stdc++.h>
using namespace std;
namespace IO{
inline int read(){
char ch=getchar(); int x=0,f=1;
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
inline void write(int x,char sp){
char ch[20]; int len=0;
if(x<0){ putchar('-'); x=~x+1; }
do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
}
inline int max(int x,int y){ return x<y?y:x; }
inline int min(int x,int y){ return x<y?x:y; }
inline void swap(int& x,int& y){ x^=y^=x^=y; }
inline void ckmax(int& x,int y){ x=x<y?y:x; }
inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;
const int NN=1e5+5,MM=5e5+5;
int t,n,m,mx,ans,pos,ban,idx,to[MM],nex[MM],head[NN],dis[NN],pre[NN];
int l,r,q[NN],in[NN],deg[NN];
bool vis[NN];
vector<int>vec;
inline void add(int a,int b){
to[++idx]=b; nex[idx]=head[a]; head[a]=idx; ++in[b];
}
void topo(){
l=1; r=0;
for(int i=1;i<=n;i++)
if(!in[i]&&ban!=i) pre[i]=0, dis[i]=0, q[++r]=i;
while(l<=r){
int x=q[l++];
if(dis[x]>mx) mx=dis[x];
for(int i=head[x];i;i=nex[i]) if(in[to[i]]&&ban!=to[i]){
--in[to[i]];
if(!in[to[i]]){
pre[to[i]]=x;
dis[to[i]]=dis[x]+1;
q[++r]=to[i];
}
}
}
}
signed main(){
FILE *R=freopen("johnny.in","r",stdin);
FILE *W=freopen("johnny.out","w",stdout);
t=read();
while(t--){
n=read(); m=read();
mx=ban=idx=0; vec.clear();
for(int i=1;i<=n;i++) in[i]=head[i]=vis[i]=0;
for(int a,b,i=1;i<=m;i++)
a=read(),b=read(), add(a,b);
for(int i=1;i<=n;i++) deg[i]=in[i];
topo(); ans=mx; pos=INT_MAX;
for(int i=1;i<=n;i++) if(dis[i]==mx){
int x=i;
while(x) vec.push_back(x), x=pre[x];
}
for(int i=0;i<vec.size();i++) if(!vis[vec[i]]){
ban=vec[i]; mx=0; vis[ban]=1;
for(int j=1;j<=n;j++) in[j]=deg[j];
for(int j=head[ban];j;j=nex[j]) --in[to[j]];
topo();
if(mx<ans||(mx==ans&&ban<pos)) ans=mx, pos=ban;
}
write(pos,' '); write(ans,'\n');
}
}
T2 贝尔数
模数不是质数就很搞。。
发现分解质因数后模数是五个一次的两位质数相乘,题目还给了模质数意义下的同余公式,于是可以先求出模五个质数意义下这一位贝尔数的值,然后再用中国剩余定理解个同余方程合并即可。
对每个质数可以先预处理前四十多个贝尔数,然后矩阵加速递推。
个人认为挺神的题(主要是数学跟矩阵都太菜了
\(code:\)
T2
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace IO{
inline int read(){
char ch=getchar(); int x=0,f=1;
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
inline void write(int x,char sp){
char ch[20]; int len=0;
if(x<0){ putchar('-'); x=~x+1; }
do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
}
inline int max(int x,int y){ return x<y?y:x; }
inline int min(int x,int y){ return x<y?x:y; }
inline void swap(int& x,int& y){ x^=y^=x^=y; }
inline void ckmax(int& x,int y){ x=x<y?y:x; }
inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;
const int NN=1010,mod=95041567;
int T,n,nul,c[50][50],bell[50],pre[6],calc[6];
int pri[6]={0,31,37,41,43,47};
namespace Crt{
int exgcd(int a,int b,int& x,int& y){
if(!b){
x=1; y=0;
return a;
}
int g=exgcd(b,a%b,x,y),z;
z=y; y=x-a/b*y; x=z;
return g;
}
void init(){
bell[0]=1;
for(int i=0;i<50;i++) c[i][0]=1;
for(int i=1;i<50;i++) 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<50;i++) for(int j=0;j< i;j++)
(bell[i]+=c[i-1][j]*bell[j]%mod)%=mod;
for(int i=1;i<6;i++){
int g=exgcd(pri[i],mod/pri[i],nul,pre[i]);
pre[i]=(pre[i]%mod+mod)%mod; pre[i]=(mod/pri[i])*pre[i]%mod;
}
}
int solve(){
int res=0;
for(int i=1;i<6;i++) (res+=pre[i]*calc[i])%=mod;
return res;
}
} using namespace Crt;
namespace Matrix{
struct matrix{
int s[50][50];
void clr(){ memset(s,0,sizeof(s)); }
void pre(){ clr(); for(int i=0;i<50;i++) s[i][i]=1; }
void print(){for(int i=0;i<50;++i)for(int j=0;j<50;++j)write(s[i][j],j==49?'\n':' ');}
}mat[6],base[6];
matrix mul(matrix x,matrix y,int z){
matrix res; res.clr();
for(int i=0;i<50;i++)
for(int k=0;k<50;k++)
for(int j=0;j<50;j++)
(res.s[i][j]+=x.s[i][k]*y.s[k][j]%z)%=z;
return res;
}
void qpow(matrix& a,matrix b,int c,int d){
while(c){
if(c&1) a=mul(a,b,d);
b=mul(b,b,d);
c>>=1;
}
}
void prework(){
for(int i=1;i<6;i++){
for(int j=0;j<pri[i];j++) mat[i].s[1][j]=bell[j]%pri[i];
base[i].pre();
base[i].s[1][0]=base[i].s[0][pri[i]-1]=base[i].s[1][pri[i]-1]=1;
for(int j=1;j<pri[i]-1;j++) base[i].s[j+1][j]=1;
}
}
} using namespace Matrix;
signed main(){
FILE *R=freopen("bell.in","r",stdin);
FILE *W=freopen("bell.out","w",stdout);
T=read(); init();
while(T--){
n=read(); prework();
for(int i=1;i<6;i++){
qpow(mat[i],base[i],n/pri[i],pri[i]);
calc[i]=mat[i].s[1][n%pri[i]];
}
write(solve(),'\n');
}
return 0;
}
T3 穿越广场
考完后发现这好像是个AC自动机套路题,但奈何时间久远,学的时候写的太快没多思考总结,于是SB了。
设\(f_{i,j,k,l}\)为\(DP\)到第\(i\)位,填了\(j\)个\(R\),在自动机中走到第\(k\)个节点,结束状态为\(l\)的方案数。
\(l\)为二进制状态,有两位。
于是有
\(\huge{f_{i,j,k,l} \to f_{i+1,j,to[k]['D'],l|end[to[k]['D']]}}\)
\(\huge{f_{i,j,k,l} \to f_{i+1,j+1,to[k]['R'],l|end[to[k]['R']]}}\)
初始状态\(f_{0,0,1,0}=1\)。
注意每个点继承它\(fail\)的状态即可。
\(code:\)
T3
#include<bits/stdc++.h>
#define int long long
#define ULL unsigned long long
using namespace std;
namespace IO{
inline int read(){
char ch=getchar(); int x=0,f=1;
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
inline void write(int x,char sp){
char ch[20]; int len=0;
if(x<0){ putchar('-'); x=~x+1; }
do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
}
inline int max(int x,int y){ return x<y?y:x; }
inline int min(int x,int y){ return x<y?x:y; }
inline void swap(int& x,int& y){ x^=y^=x^=y; }
inline void ckmax(int& x,int y){ x=x<y?y:x; }
inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;
const int NN=110,p=1e9+7;
int t,n,m,ext,ans,f[NN<<1][NN][NN<<1][4];
char ch[NN];
namespace AC_automaton{
int root,tot,to[NN<<1][2],fail[NN<<1],end[NN<<1];
void insert(char *s){
int len=strlen(s),u=1;
for(int i=0;i<len;i++){
int now=(s[i]=='R');
if(!to[u][now]) to[u][now]=++tot, end[tot]=0;
u=to[u][now];
}
end[u]=root?2:1;
if(!root) root=1;
}
void build(){
queue<int>q;
if(to[root][0]) q.push(to[root][0]), fail[to[root][0]]=root;
else to[root][0]=root;
if(to[root][1]) q.push(to[root][1]), fail[to[root][1]]=root;
else to[root][1]=root;
while(!q.empty()){
int u=q.front(); q.pop();
end[u]|=end[fail[u]];
if(to[u][0]) fail[to[u][0]]=to[fail[u]][0], q.push(to[u][0]);
else to[u][0]=to[fail[u]][0];
if(to[u][1]) fail[to[u][1]]=to[fail[u]][1], q.push(to[u][1]);
else to[u][1]=to[fail[u]][1];
}
}
} using namespace AC_automaton;
signed main(){
FILE *R=freopen("square.in","r",stdin);
FILE *W=freopen("square.out","w",stdout);
t=read();
while(t--){
m=read(); n=read(); tot=1; root=0; ext=n+m; ans=0;
memset(f,0,sizeof(f));
memset(to,0,sizeof(to));
memset(fail,0,sizeof(fail));
scanf("%s",ch); insert(ch);
scanf("%s",ch); insert(ch);
build(); f[0][0][1][0]=1;
for(int i=0;i<ext;i++)
for(int j=0;j<=m;j++){
if(j>i||i-j>n) continue;
for(int k=1;k<=tot;k++)
for(int u=0;u<4;u++){
(f[i+1][j ][to[k][0]][u|end[to[k][0]]]+=f[i][j][k][u])%=p;
(f[i+1][j+1][to[k][1]][u|end[to[k][1]]]+=f[i][j][k][u])%=p;
}
}
for(int i=1;i<=tot;i++) (ans+=f[ext][m][i][3])%=p;
write(ans,'\n');
}
return 0;
}
T4 舞动的夜晚
先跑最大流,然后在残量网络上跑\(tarjan\),如果边在\(SCC\)里说明它没有影响。
改的有点ex,待补
2021.9.21考试总结[NOIP模拟58]的更多相关文章
- 2021.8.21考试总结[NOIP模拟45]
T1 打表 由归纳法可以发现其实就是所有情况的总和. $\frac{\sum_{j=1}^{1<<k}(v_j-v_{ans})}{2^k}$ $code:$ 1 #include< ...
- 2021.7.21考试总结[NOIP模拟22]
终于碾压小熠了乐死了 T1 d 小贪心一波直接出正解,没啥好说的(bushi 好像可以主席树暴力找,但我怎么可能会呢?好像可以堆优化简单找,但我怎么可能想得到呢? 那怎么办?昨天两道单调指针加桶,我直 ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- 2021.9.13考试总结[NOIP模拟52]
T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...
- 2021.8.11考试总结[NOIP模拟36]
T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...
- 2021.7.29考试总结[NOIP模拟27]
T1 牛半仙的妹子图 做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数. 我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm ...
- 2021.7.15考试总结[NOIP模拟16]
ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...
- 2021.9.14考试总结[NOIP模拟53]
T1 ZYB和售货机 容易发现把每个物品都买成$1$是没有影响的. 然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以 ...
- 2021.9.12考试总结[NOIP模拟51]
T1 茅山道术 仔细观察发现对于每个点只考虑它前面第一个与它颜色相同的点即可. 又仔细观察发现对一段区间染色后以这个区间内点为端点的区间不能染色. 于是对区间右端点而言,区间染色的贡献为遍历到区间左端 ...
随机推荐
- SQL-DELETE触发器练习
&练习一 如下所示三张表( student,grade,student_updata_before ): student表 grade表 Student_update_before表 # 触发 ...
- 关于JDK高版本下RMI、LDAP+JNDI bypass的一点笔记
1.关于RMI 只启用RMI服务时,这时候RMI客户端能够去打服务端,有两种情况,第一种就是利用服务端本地的gadget,具体要看服务端pom.xml文件 比如yso中yso工具中已经集合了很多gad ...
- 马哈鱼数据血缘分析器分析case-when语句
马哈鱼数据血缘分析器是一个分析数据血缘关系的平台,可以在线直接递交 SQL 语句进行分析,也可以选择连接指定数据库获取 metadata.从本地上传文件目录.或从指定 git 仓库获取脚本进行分析. ...
- sync 修饰符在Vue中如何使用
在有些情况下,我们可能需要对一个 prop 进行"双向绑定".不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源. 这 ...
- yield实现 coroutine协程案例
yield可以手工实现协程,但python为我们封装了一个greenlet,先看看yield实现,yield需要手工操作,无法实现IO操作时自动切换协程,greenlet是封装好的,能方便使用io切换 ...
- 30天自制操作系统(二)汇编语言学习和Makefile入门
我们继续学习操作系统的相关内容. ; hello-os ; TAB=4 ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのた ...
- php发送邮件方法-亲测可用,email.class.php过期解决办法
php虽然提供了mail()函数,但并不好用,而PHPMailer是一个不错的邮件发送工具,使用起来也是非常简单!使用PHPMailer发送邮件: <?php header("cont ...
- seo优化刷百度指数方法
站长朋友们都听过"刷指数"这个概念,并且一直以来都有站长刷指数的现象.大家或为了提升网站数据,或为了满足排名的虚荣心,或为了与竞争对手抗衡,都或多或少研究过刷指数的原理和工具. 那 ...
- hdu5909-Tree Cutting【FWT】
正题 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5909 题目大意 给出\(n\)和\(m\)(\(m=2^k\)).再给出一个大小为\(n\)的树 ...
- Javascript 常见的高阶函数
高阶函数,英文叫 Higher Order function.一个函数可以接收另外一个函数作为参数,这种函数就叫做高阶函数. 示例: function add(x, y, f) { return f( ...