• CF772C Vulnerable Kerbals 图论+数论gcd


    题意:

    给出m,n,再给一个m个数的集合让你构造一个序列满足以下的条件:

    1.这个序列的所有数都在0-m-1之间(含)

    2.这个数列的所有前缀积模(m)都不同

    3.所有的前缀积模(m)都不能出现在给你的集合中

    4.最大化这个序列的长度

    输出任意满足条件的序列。

    范围&性质:(1le n le 2 imes 10^5)

    分析:

    根据题意列出同余方程,我们可以发现当余数从一个点向另一个点转移时,存在(gcd(i,m)|j) ,这样复杂度是(O(n^2))的,需要进行优化,我们发现对于(gcd(i,m)=gcd(j,m))的点对(i,j)他们在图上连的边是相同的,所以我们可以把这样的点的集合看成一个点,整张图就转化成了在DAG上求一个带权最长链,直接DP就好了

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 2e5+5;
    	long long n,m;
    	long long f[maxn],nxt[maxn];
    	bool vis[maxn];
    	vector<long long> v[maxn];
    	
    	long long gcd(long long a,long long b)
    	{
    		return b==0?a:gcd(b,a%b);
    	}
    	
    	long long exgcd(long long a,long long b,long long &x,long long &y)
    	{
    		if(b==0)
    		{
    			x=1;y=0;
    			return a;
    		}
    		long long tmp=exgcd(b,a%b,x,y);
    		long long d=x;
    		x=y;
    		y=d-(a/b)*y;
    		return tmp;
    	}
    	
    	long long cal(long long a,long long b,long long c)
    	{
    		long long x,y;
    		long long d=exgcd(a,b,x,y);
    		if(c%d) return  -1;
    		x=x*c/d;
    		b/=d;
    		x=(x%b+b)%b;
    		return x;
    	}
    	
    	void dfs(long long u)
    	{
    		if(f[u]) return ;
    		long long res=0;
    		for(int i=u*2;i<m;i+=u)
    		{
    			if(v[i].size())
    			{
    				dfs(i);
    				if(f[i]>res)
    				{
    					res=f[i];
    					nxt[u]=i;
    				}
    			}
    		}
    		f[u]=res+v[u].size();
    	}
    	
    	void work()
    	{
    		memset(f,0,sizeof(f));
    		scanf("%lld%lld",&n,&m);
    		for(long long i=1,x;i<=n;i++)
    		{
    			scanf("%lld",&x);
    			vis[x]=true;
    		}
    		for(long long i=1;i<m;i++)
    		{
    			if(vis[i]) continue;
    			long long tmp=gcd(i,m);
    			v[tmp].push_back(i);
    		}
    		dfs(1);
    		printf("%lld
    ",f[1]+(!vis[0]));
    		long long u=1,lst=1;
    		while(u)
    		{
    			for(int i=0;i<v[u].size();i++)
    			{
    				long long tmp=v[u][i];
    				long long ans=cal(lst,m,tmp);
    				printf("%lld ",ans);
    				lst=tmp;
    			}
    			u=nxt[u];
    		}
    		if(!vis[0]) printf("0
    ");
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
  • 相关阅读:
    快速搭建Android 开发环境-使用ADT Bundle
    js window.print ()只打印网页图片
    数据范式的理解与解析技巧
    C#/.Net文件打包下载
    动态加载echarts数据,防止动态加载后数据叠加
    忙忙碌碌程序媛的工作小知识
    动态数据库名称的时候,使用sp_executesql
    C#的NPOI根据模板导出动态EXCEL图表,
    Android 安卓实现页面相互跳转并相互传递参数
    C#编码规范
  • 原文地址:https://www.cnblogs.com/youth518/p/13694591.html
Copyright © 2020-2023  润新知