2017/10/6模拟赛总结
来源:互联网 发布:淘宝卖家发布宝贝流程 编辑:程序博客网 时间:2024/06/01 19:18
题目来自NOIP2016十连测第6场
过了若干天才填完坑..
不得不说这一场题目真是太巧(bian)妙(tai)了
T1 幻想
所有数据都很大= =
首先看到
那么应该就只能枚举了
正好多组数据一共枚举最多
分析
然而枚举就要求必须是
打表找规律!
012 120 201 120 201 012 201 012 120…
1 1 2 1 1 2 1 1
先把它看做每次加上1然后%
这样会有一些位置多加了一些数
然后把这些位置的
就会发现
于是可以对于每组数据 先求出第
然后从
由于过于逼近时限 需要卡常
比如取地址比运算快 register等黑科技
因此代码就异常的丑=
#include<bits/stdc++.h>using namespace std;#define Add(x) x=inc[x]#define ADD(x) x=Inc[x]#define mo 20000116int k;int calc(long long x,long long base){ if (base==1) return x-1; else return (calc((x-1)%base+1,base/k)+(x-1)/base)%k;}int main(){ int inc[1010],Inc[1010],A[60],Case; register int j; scanf("%d",&Case); for (j=0;j<1000;j++) inc[j]=Inc[j]=j+1; while (Case--){ long long l,r; scanf("%d%lld%lld",&k,&l,&r); inc[k-1]=0; register long long i,base=1,x=l; while (base*k<l+1) base*=k; register int t=calc(l+1,base),p=l%mo; memset(A,0,sizeof(A)); j=1; while (x){ A[j]=x%k; x/=k; ADD(j); } register unsigned int ans=(1LL*p*p+l+804)/233*t; for (i=l+1;i<=r;i++){ j=1; Add(t); while (A[j]==k-1){ A[j]=0; Add(t); ADD(j); } ADD(A[j]); p++; if (p==mo) p=0; ans+=(1LL*p*p+i+804)/233*t; } printf("%u\n",ans); inc[k-1]=k; } return 0;}
T2 告别
一个比较简单的想法是用
由于状态有
考虑优化状态的设计
每天的操作是把三元组置换一遍 因此排列里的具体数字是无关紧要的 只和数字的关系有关
如果依照置换的方式定义 把不在自己位置上的数字连到自己位置上 就会形成若干个环
例:2 3 1 4 6 5 中有 2-3-1 4 6-5 三个环
因此可以依据环的大小和数量定义状态
用map映射一下即可
打表发现最多不会超过140个本质不同的状态
然后就可以用矩阵快速幂转移dp了
因为所有环的本质是一样的 转移的时候随便造出一个满足的排列即可
由于一个置换可能对应很多排列 直接做不能保证正确性
观察到
然后由于是计算概率 dp中用到了逆元
另外可以把vector映射用
讲道理这dp也太鬼畜了吧
#include<bits/stdc++.h>using namespace std;#define N 20#define M 140#define mo 998244353map<vector<int>,int>mp;vector<int>A,P[M];int tot,n,m,a[N],b[N],id[N],B[N];bool vis[N];struct Matrix{ int s[M][M]; Matrix(){memset(s,0,sizeof(s));} friend Matrix operator *(Matrix A,Matrix B){ Matrix C; int i,j,k; for (i=1;i<M;i++) for (j=1;j<M;j++) if (A.s[i][j]) for (k=1;k<M;k++) C.s[i][k]=(C.s[i][k]+1LL*A.s[i][j]*B.s[j][k])%mo; return C; }}I;void Pow(Matrix &G,int y){ Matrix tmp=I; while (y){ if (y&1) G=G*tmp; y>>=1; tmp=tmp*tmp; }}void dfs(int l,int sum){ if (sum==n){ mp[A]=++tot; P[tot]=A; return; } int i; for (i=l;i<=n-sum;i++){ A.push_back(i); dfs(i,sum+i); A.pop_back(); }}void To_Array(int x,int *G){ A=P[x]; int i,j,k=1; for (i=0;i<A.size();i++){ for (j=0;j<A[i]-1;j++) G[j+k]=j+k+1; G[j+k]=k; k+=A[i]; }}int To_Vector(int *G){ A.clear(); memset(vis,0,sizeof(vis)); int i; for (i=1;i<=n;i++){ if (vis[i]) continue; int cnt=0,x=i; do{ vis[x]=1; x=G[x]; cnt++; }while (x!=i); A.push_back(cnt); } sort(A.begin(),A.end()); return mp[A];}int Inv(int x){ int res=1,y=mo-2; while (y){ if (y&1) res=1LL*res*x%mo; y>>=1; x=1LL*x*x%mo; } return res;}void Init(){ A.clear(); dfs(1,0); int i,j,k,l,all=Inv(n*(n-1)*(n-2)); I.s[1][1]=1; for (i=2;i<=tot;i++) for (j=1;j<=n;j++) for (k=1;k<=n;k++){ if (j==k) continue; for (l=1;l<=n;l++){ if (j==l || k==l) continue; To_Array(i,B); int tmp=B[j]; B[j]=B[k]; B[k]=B[l]; B[l]=tmp; int t=To_Vector(B); I.s[i][t]=(I.s[i][t]+all)%mo; } }}int main(){ scanf("%d%d",&n,&m); Init(); int i; for (i=1;i<=n;i++) scanf("%d",&a[i]); for (i=1;i<=n;i++) scanf("%d",&b[i]),id[b[i]]=i; for (i=1;i<=n;i++) a[i]=id[a[i]]; Matrix dp; dp.s[1][To_Vector(a)]=1; Pow(dp,m); printf("%d\n",dp.s[1][1]); return 0;}
T3 现实
首先分析一下模型
答案一定在环上
把一个点分成入点和出点 之后一条边断开可以成立就代表了一个点成立
先找一个环出来
如果找不到环 所有点都可以当做答案
然后拓扑排序一波
如果还有环 就说明无解
这之后就会发现有两种环套环的情况
X代表不能作为答案
根据环的不同方向 找出向左和向右可以到达的最大/最小编号
代码中Mn/Mx对应第1种 Mx1对应第2种
分类讨论即可
看起来只需要求Mn即可 但是会出现这种情况
右边的点Mn会变成最左边的点 而事实上中间的那个点也不能作为答案
所以就会有Mx 访问到中间那个点时就会排除这种情况
#include<bits/stdc++.h>using namespace std;#define N 1000010struct edge{ int nxt,t;}e[N<<2];int n,m,gn,head[N],edge_cnt,vis[N],fa[N],F[N],Cir[N],cir_cnt,ans[N],ans_cnt,Mx[N],Mn[N],Mx1[N],Deg[N],Q[N],sum[N];bool used[N<<2],Find;void add_edge(int x,int y){ e[edge_cnt]=(edge){head[x],y}; head[x]=edge_cnt++;}void dfs(int x){ vis[x]=1; int i; for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t; if (!vis[to]){ fa[to]=x; F[to]=i; dfs(to); } else if (vis[to]==1){ int y=x; while (y!=to){ Cir[++cir_cnt]=y; used[F[y]]=1; y=fa[y]; } Cir[++cir_cnt]=to; Find=1; } if (Find) return; } vis[x]=2;}bool Top(){ int l=1,r=0,i,j; for (i=1;i<=gn;i++) for (j=head[i];~j;j=e[j].nxt) if (!used[j]) Deg[e[j].t]++; for (i=1;i<=gn;i++) if (!Deg[i]) Q[++r]=i; while (l<=r){ int x=Q[l++]; for (i=head[x];~i;i=e[i].nxt){ if (used[i]) continue; int to=e[i].t; Deg[to]--; if (!Deg[to]) Q[++r]=to; } } return r==gn;} void solve(){ int i,j; for (i=1;i<=n;i++) if (!vis[i]){ dfs(i); if (Find) break; } if (!Find){ for (i=1;i<=n;i++) ans[++ans_cnt]=i; return; } if (!Top()) return; memset(Mn,63,sizeof(Mn)); reverse(Cir+1,Cir+cir_cnt+1); for (i=1;i<=cir_cnt;i++) Mn[Cir[i]]=Mx[Cir[i]]=Mx1[Cir[i]]=i; for (i=gn;i;i--){ int x=Q[i]; for (j=head[x];~j;j=e[j].nxt){ if (used[j]) continue; int to=e[j].t; Mn[x]=min(Mn[x],Mn[to]); Mx1[x]=max(Mx1[x],Mx1[to]); } } for (i=1;i<=gn;i++){ int x=Q[i]; for (j=head[x];~j;j=e[j].nxt){ if (used[j]) continue; int to=e[j].t; Mx[to]=max(Mx[to],Mx[x]); } } for (i=1;i<=cir_cnt;i++){ if (Mn[Cir[i]]<i){ sum[1]++; sum[Mn[Cir[i]]+1]--; sum[i+1]++; } if (Mx[Cir[i]]>i){ sum[1]++; sum[i]--; sum[Mx[Cir[i]]+1]++; } if (Mx1[Cir[i]]>i){ sum[i+1]++; sum[Mx1[Cir[i]]+1]--; } } int tmp=0; for (i=1;i<=cir_cnt;i++){ tmp+=sum[i]; if (!tmp && Cir[i]>n) ans[++ans_cnt]=Cir[i]-n; }} int main(){ memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); gn=n*2; int i; for (i=1;i<=n;i++) add_edge(i,i+n); for (i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); add_edge(x+n,y); } solve(); printf("%d\n",ans_cnt); sort(ans+1,ans+1+ans_cnt); for (i=1;i<=ans_cnt;i++) printf("%d ",ans[i]); return 0;}
Date:2017/10/11
By CalvinJin
- 2017/10/6模拟赛总结
- 2017/10/10模拟赛总结
- 2017/11/6模拟赛总结
- 2017/10/7模拟赛总结
- 2017/10/9模拟赛总结
- 2017/10/12模拟赛总结
- 2017/10/15模拟赛总结
- 2017/10/16模拟赛总结
- 2017/10/21模拟赛总结
- 2017/10/23模拟赛总结
- 2017/10/25模拟赛总结
- 2017/10/30模拟赛总结
- NOIP2017模拟赛(6) 总结
- NOIP2017模拟赛(10) 总结
- 10-5&&10-6NOIP模拟赛总结
- 2017/11/3模拟赛总结
- 2017/11/4模拟赛总结
- 2017/11/5模拟赛总结
- 我的第001天学习记录
- 顺序表
- String相关知识
- StringBuilder类的常用方法 增删改查、反转、互转
- levelDB的效率
- 2017/10/6模拟赛总结
- 关联规则挖掘
- UVA 107 The Cat in the Hat
- 如何通俗易懂地解释卷积?
- 树的广度(深度)优先遍历算法
- 使用jstack分析cpu消耗过高的问题
- QT(2):添加ui文件及构建ui文件的头文件说明
- 【UVA 10034 Freckles】& Kruskal & 最小生成树
- spring学习