CF800 C
来源:互联网 发布:matlab生成随机数矩阵 编辑:程序博客网 时间:2024/06/02 05:06
题意:
在模m的意义下,ban掉n个数。构造一个最长的数列,使得:
1、前缀之积两两不等
2、前缀之积不能出现n个被ban的值
n< m<=200000
#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<iostream>#include<vector>#define N 410000#define pb push_backusing namespace std;struct node{int x,y,nex;}a[20*N];int n,m,len,fir[N],f[N],g[N],sta[N],belong[N],tp,dfn[N],low[N],id,cnt,du[N],e[N*20][2];int p[N*20],tail,ans,w,A[N],res[N],num,fr[N];bool b[N],insta[N];vector<int> v[N];void ins(int x,int y){ a[++len].x=x;a[len].y=y;a[len].nex=fir[x];fir[x]=len;}int gcd(int a,int b){ if(b==0) return a; return gcd(b,a%b);}void tarjan(int x,int fa){ dfn[x]=low[x]=++id; sta[++tp]=x;insta[x]=1; for(int k=fir[x];k;k=a[k].nex) { int y=a[k].y; if(dfn[y]==0) {tarjan(y,x);low[x]=min(low[x],low[y]);} else if(insta[y]) low[x]=min(low[x],dfn[y]); } if(low[x]>dfn[fa]) { cnt++; int y; do{ y=sta[tp];sta[tp--]=0; insta[y]=0; belong[y]=cnt; g[cnt]+=b[y]; v[cnt].pb(y); }while(y!=x); int o=1; }}void tpsort(){ for(int i=1;i<=cnt;i++) if(du[i]==0) f[i]=g[i],p[++tail]=i; for(int i=1;i<=tail;i++) { int x=p[i]; if(f[x]>ans) {ans=f[x];w=x;} for(int k=fir[x];k;k=a[k].nex) { int y=a[k].y; du[y]--; if(f[x]+g[y]>f[y]) {f[y]=f[x]+g[y];fr[y]=x;} if(du[y]==0) p[++tail]=y; } }}int exgcd(int a,int b,int &x,int &y){ if(b==0) {x=1;y=0;return a;} int t=a/b,xx,yy,g; g=exgcd(b,a%b,xx,yy); x=yy;y=xx-t*yy; return g;}void make_ans(){ int x=w; while(x) { int siz=v[x].size(); for(int i=0;i<siz;i++) if(b[v[x][i]]) A[++num]=v[x][i]; x=fr[x]; } res[1]=A[1]; for(int i=2;i<=num;i++) { int x,y,g;g=exgcd(A[i-1],m,x,y); x=(x%m+m)%m; x=1ll*x*(A[i]/g)%m; res[i]=x; } if(b[0]) res[++num]=0; printf("%d\n",num); for(int i=1;i<=num;i++) printf("%d ",res[i]);}int main(){ scanf("%d%d",&n,&m); for(int i=0;i<m;i++) b[i]=1; for(int i=1;i<=n;i++) { int x;scanf("%d",&x); b[x]=0; } for(int i=1;i<m;i++) { int g=gcd(i,m); ins(i,g+m); } for(int i=1;i<m;i++) for(int j=i;j<m;j+=i) ins(i+m,j); for(int i=1;i<m;i++) if(dfn[i]==0) tarjan(1,0); for(int i=1;i<=len;i++) e[i][0]=a[i].x,e[i][1]=a[i].y; for(int i=1;i<=2*m;i++) fir[i]=0; int tmp=len;len=0; for(int i=1;i<=tmp;i++) { int x=belong[e[i][0]],y=belong[e[i][1]]; if(x!=y) {ins(y,x);du[x]++;} } tpsort(); make_ans(); return 0;}
题解:
直接做一个前缀积的数列,变回原数列是容易的
在能一次转移到的数字间连边,缩点后拓补图dp一下就可以了
直接连边是
考虑
那么对于一个数字i,连上
复杂度
现场做的时候一直在想原根,按二的幂分组什么的。。先入为主了,实在不应该
0 0
- CF800 C
- c
- c
- c
- c
- C
- c
- c
- c
- C+
- c
- C
- c
- c
- c
- C
- C
- c
- freemodbus移植讲解 ZZ
- Android_Touch_Test
- [置顶]第二弹:升级原创日语汉字转假名小工具1.02
- [置顶]推荐一本书:清华出版的《Modbus软件开发实战指南》
- Android触摸事件的分发机制
- CF800 C
- 前端笔记
- Chess---->简单命令框象棋(人VS人)
- WindowManager
- Android入门随记
- Ajax 跨域
- 自定义Back返回键(实现按两次返回键退出程序)
- Android 快速开发系列 打造万能的ListView GridView 适配器
- 创建弹出菜单