考前冲刺 1
Posted 一蓑烟雨任生平
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了考前冲刺 1相关的知识,希望对你有一定的参考价值。
思路:矩阵优化数列
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; long long n,a,b; long long t[2][2],ans[2][2],r[2][2]; void mul(long long a[2][2],long long b[2][2]){ memset(r,0,sizeof(r)); for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) r[i][j]+=a[i][k]*b[k][j],r[i][j]%=7; for(int i=0;i<2;i++) for(int j=0;j<2;j++) a[i][j]=r[i][j]; } int main(){ freopen("attack.in","r",stdin); freopen("attack.out","w",stdout); scanf("%lld%lld%lld",&a,&b,&n); t[0][0]=a;t[0][1]=1; t[1][0]=b; ans[0][0]=1;ans[0][1]=1; if(n==2||n==1){ cout<<"1";return 0; } n-=2; while(n){ if(n&1) mul(ans,t); mul(t,t); n>>=1; } printf("%d",ans[0][0]); }
思路:组合数学,把它拓展成一个二维平面的问题后,把物理老师看成是移动(1,0)生物老师看成是移动(0,1),那么到达(n,m)这个点。而且路线不经过对角线上方的路线总数就是答案。
然后发现这和一个问题很像,部分分可以用卡特兰数去搞一下,原理戳这里或者这里。
然后发现这还是一个组合数问题:对方向编号,向上是0,向右是1,那么从左下角走到右上角一定要经过M 个1和N个0。这个题目可以转化为从M+N个盒子中挑出M个盒子有多少种方法。
那么在不考虑对角线的情况下答案为C(m+n,m)。但是现在题目要求不能到达对角线上方,所以我们还需要减去经过对角线的上方的方案数。
原理戳这里的第三问
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int T,n,m; int main(){ freopen("fseq.in","r",stdin); freopen("fseq.out","w",stdout); scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); if(m>n){ cout<<"0.000000"<<endl;continue; } else printf("%.6lf\\n",1.0-m*1.0/(n+1)*1.0); } }
思路:首先tarjin缩点,然后跑连边dfs找出树的直径的两个端点A,B,答案就是max(dis(x,a),dis(x,b))
#include<map> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 20010 #define MAXN 200010 using namespace std; queue<int>que; map<int,int>ma[M]; int n,m,tim; int tot=1,tot1; int top,sumcol; int vis[M],visstack[M]; int col[M],dis[M],ans[M]; int dfn[M],low[M],stack[M]; int to[MAXN*2],net[MAXN*2],cap[MAXN*2],head[M]; int to1[MAXN*2],net1[MAXN*2],cap1[MAXN*2],head1[M]; void add(int u,int v,int w){ to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot; to[++tot]=u;cap[tot]=w;net[tot]=head[v];head[v]=tot; } void add1(int u,int v,int w){ to1[++tot1]=v;cap1[tot1]=w;net1[tot1]=head1[u];head1[u]=tot1; to1[++tot1]=u;cap1[tot1]=w;net1[tot1]=head1[v];head1[v]=tot1; } void tarjin(int now){ low[now]=dfn[now]=++tim; stack[++top]=now; visstack[now]=1; for(int i=head[now];i;i=net[i]){ if(vis[i]||vis[i^1]) continue; vis[i]=vis[i^1]=1; if(visstack[to[i]]) low[now]=min(low[now],dfn[to[i]]); else if(!dfn[to[i]]){ tarjin(to[i]); low[now]=min(low[now],low[to[i]]); } } if(low[now]==dfn[now]){ sumcol++; col[now]=sumcol; while(stack[top]!=now){ col[stack[top]]=sumcol; visstack[stack[top]]=0; top--; } visstack[now]=0; top--; } } void spfa(int s){ memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); while(!que.empty()) que.pop(); que.push(s); vis[s]=1;dis[s]=0; while(!que.empty()){ int now=que.front(); que.pop(); ans[s]=max(ans[s],dis[now]); for(int i=head1[now];i;i=net1[i]) if(dis[to1[i]]<dis[now]+cap1[i]){ dis[to1[i]]=dis[now]+cap1[i]; if(!vis[to1[i]]){ vis[to1[i]]=1; que.push(to1[i]); } } } } int main(){ freopen("prize.in","r",stdin); freopen("prize.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjin(i); for(int i=1;i<=n;i++) for(int j=head[i];j;j=net[j]) if(col[i]!=col[to[j]]) if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){ ma[col[i]][col[to[j]]]=1; ma[col[to[j]]][col[i]]=1; add1(col[i],col[to[j]],cap[j]); } for(int i=1;i<=sumcol;i++) spfa(i); for(int i=1;i<=n;i++) cout<<ans[col[i]]<<endl; } /* 6 6 1 4 2 1 2 6 2 5 3 2 3 7 6 3 4 3 1 8 */
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 20010 #define MAXN 200010 using namespace std; map<int,int>ma[M]; int n,m,tim; int tot=1,tot1,root; int top,maxn,sumcol; int visstack[M]; int col[M],dis[M],dis1[M]; int dfn[M],low[M],stack[M]; int to[MAXN*2],net[MAXN*2],cap[MAXN*2],head[M]; int to1[MAXN*2],net1[MAXN*2],cap1[MAXN*2],head1[M]; void add(int u,int v,int w){ to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot; to[++tot]=u;cap[tot]=w;net[tot]=head[v];head[v]=tot; } void add1(int u,int v,int w){ to1[++tot1]=v;cap1[tot1]=w;net1[tot1]=head1[u];head1[u]=tot1; to1[++tot1]=u;cap1[tot1]=w;net1[tot1]=head1[v];head1[v]=tot1; } void tarjin(int now,int fa){ low[now]=dfn[now]=++tim; stack[++top]=now; visstack[now]=1; for(int i=head[now];i;i=net[i]) if(visstack[to[i]]&&to[i]!=fa) low[now]=min(low[now],dfn[to[i]]); else if(!dfn[to[i]]){ tarjin(to[i],now); low[now]=min(low[now],low[to[i]]); } if(low[now]==dfn[now]){ sumcol++; col[now]=sumcol; while(stack[top]!=now){ col[stack[top]]=sumcol; visstack[stack[top]]=0; top--; } visstack[now]=0; top--; } } void dfs(int now,int fa){ for(int i=head1[now];i;i=net1[i]) if(to1[i]!=fa){ dis[to1[i]]=dis[now]+cap1[i]; if(dis[to1[i]]>maxn) maxn=dis[to1[i]],root=to1[i]; dfs(to1[i],now); } } void dfs1(int now,int fa){ for(int i=head1[now];i;i=net1[i]) if(to1[i]!=fa){ dis1[to1[i]]=dis1[now]+cap1[i]; dfs1(to1[i],now); } } int main(){ freopen("prize.in","r",stdin); freopen("prize.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjin(i,0); for(int i=1;i<=n;i++) for(int j=head[i];j;j=net[j]) if(col[i]!=col[to[j]]) if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){ ma[col[i]][col[to[j]]]=1; ma[col[to[j]]][col[i]]=1; add1(col[i],col[to[j]],cap[j]); } dfs(1,-1); maxn=0; memset(dis,0,sizeof(dis)); dfs(root,-1); maxn=0; dfs1(root,-1); for(int i=1;i<=n;i++) cout<<max(dis[col[i]],dis1[col[i]])<<endl; } /* 6 6 1 4 2 1 2 6 2 5 3 2 3 7 6 3 4 3 1 8 */
以上是关于考前冲刺 1的主要内容,如果未能解决你的问题,请参考以下文章