• Vulnerable Kerbals CodeForces


    根据拓展欧几里得对于同余方程 $ax+by=c$ ,有解的条件是 $(a,b)|c$。

    那么对于构造的序列的数,前一个数 $a$  和后一个数 $b$ ,应该满足 $a*x=b(mod m)$ 即 $ax+my=b$;

    建图时,遍历 $0 o m-1$,对于没有标记的数 $i$ ,在 $gcd(i,m)$ 和 $i$ 之间连边。

    但是,仅仅如此只是把每个数和其与m的最大公因数相连,还有些情况没有考虑。只要满足 $(a,m)|b$,那么 $a,b$就可以连边。

    对于一个点,如果他指向的点也是一个起点的话,那么两部分之间是可以相互连接的。

    那么,就可以一组一组地找。

    然后是 $DAG$ 图上求最长路,还不太会。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=2e5+5;
     4 int nxt[N],dp[N];
     5 vector<int>pic[N];
     6 bool vis[N];
     7 typedef long long ll;
     8 int n,m;
     9 ll exgcd(ll a,ll b,ll &x,ll &y)//拓展欧几里得
    10 {
    11     if(!b)
    12     {
    13         x=1;
    14         y=0;
    15         return a;
    16     }
    17     ll res=exgcd(b,a%b,x,y);
    18     ll tmp=x;
    19     x=y;
    20     y=tmp-(a/b)*y;
    21     return res;
    22 }
    23 ll cal(ll a,ll b,ll c)
    24 {
    25     ll x,y;
    26     ll gcd=exgcd(a,b,x,y);
    27     if(c%gcd)
    28         return -1;
    29     x=c/gcd*x;
    30     b/=gcd;
    31     x=(x%b+b)%b;
    32     return x;//最小非负解
    33 }
    34 void dfs(int p)
    35 {
    36     if(dp[p]) return;
    37     int res=0;
    38     for(int i=p*2;i<m;i+=p)
    39     {
    40         if(pic[i].size())
    41         {
    42             dfs(i);
    43             if(dp[i]>res)//求最大
    44             {
    45                 res=dp[i];
    46                 nxt[p]=i;//存下一个点
    47             }
    48         }
    49     }
    50     dp[p]=res+pic[p].size();
    51 }
    52 int main()
    53 {
    54     while(scanf("%d%d",&n,&m)!=EOF)
    55     {
    56         memset(vis,0,sizeof(vis));
    57         for(int i=0;i<m;i++)
    58             pic[i].clear();
    59         memset(dp,0,sizeof(dp));
    60         memset(nxt,0,sizeof(nxt));
    61         int a;
    62         for(int i=1;i<=n;i++)
    63         {
    64             scanf("%d",&a);
    65             vis[a]=1;
    66         }
    67         for(int i=1;i<m;i++)
    68         {//建图
    69             if(!vis[i])
    70             {
    71                 int t=__gcd(i,m);//以和m的最小公因数为源点建立边 
    72                 pic[t].push_back(i);
    73             }
    74         }
    75         dfs(1);
    76         printf("%d
    ",dp[1]+(!vis[0]));
    77         int u=1,v=1;
    78         while(u)
    79         {//在路径上求解同余方程
    80             for(int i=0;i<pic[u].size();i++)
    81             {
    82                 int t=pic[u][i];
    83                 int ans=(int)cal((ll)v,(ll)m,(ll)t);
    84                 printf("%d
    ",ans);
    85                 v=t;
    86             }
    87             u=nxt[u];
    88         }
    89         if(!vis[0])
    90             printf("0
    ");
    91     }
    92     return 0;
    93 }
    View Code
  • 相关阅读:
    [探索][管理]《现在,发现你的优势》
    【成功智慧】010.依靠忍耐度过困难时期
    爱情五十九课,就差一句话
    VSS2005 托管 VS2010代码
    一个网站的金字塔战略
    【成功智慧】013.脚踏实地的去做,没有完不成的任务
    MU.Bread 麦卡优娜
    【成功智慧】012.要有耐心去等待成功的到来
    【成功智慧】009.要能够承受所发生的事情
    【成功智慧】014.一日复一日的度过难关
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/12111745.html
Copyright © 2020-2023  润新知