UVA 1635 Irrelevant Elements (唯一分解定理+组合数的递推公式)

25 篇文章 0 订阅

UVA 1635 Irrelevant Elements (唯一分解定理+组合数的递推公式)

给出n个数a1,a2,…,an,相邻两个数两两相加直到合并成一个数A,问A/m的结果与a1,a2,…,an哪些数无关。

显然题目要找的是对于A=c1a1+c2a2,…,cnan,有哪些ai前面的系数是可以被m整除的。

且可以发现对于ai前面的系数ci=C(n-1,i-1),因为当n较大时,组合数会很大以至于long long都存不下,所以可以根据组合数的递推公式,得到组合数的素因子分解式,来判断当前系数是否可以被m整除。

C(n,k)=C(n,k-1)*(n-k+1)/k

先把m的素因子分解式求出并储存,逐一遍历m的素因子(pi,ei),再通过一个循环遍历[2,n/2]中的数,并维护循环中的数的质因子分解式中pi的系数e。如果当前e<ei,则当前组合数不可能整除m。

对于C(n-1,k-1),有C(n-1,i-1)=C(n-1,n-i)
所以如果ai能被m整除,那么an-i+1也能被m整除。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int max_n=1e6+5;
int n;
long long m;
typedef pair<int,int> P;
vector<P> m_factor;
bool vis[max_n];
void get_m_factor(long long m)
{
	m_factor.clear();
	int q=(int)sqrt(m+0.5);
	for(int i=2;i<=q;i++)
	if(m%i==0)
	{
		int cnt=0;
		while(m%i==0)
		{
			cnt++;
			m/=i;
		}
		m_factor.push_back(make_pair(i,cnt));
		if(m==1)break;
	}
	if(m!=1)m_factor.push_back(make_pair(m,1));
}
void solve(void)
{
	get_m_factor(m);
	memset(vis,0,sizeof(vis));
	vector<int> ans;
	for(int i=0;i<m_factor.size();i++)
	{
		int p=m_factor[i].first;
		int e=m_factor[i].second;
		int cnt=0;
		for(int j=2;j<=(n+1)/2;j++)
		{
			int x=n-j+1;
			while(x%p==0)cnt++,x/=p;
			x=j-1;
			while(x%p==0)cnt--,x/=p;
			if(cnt<e)vis[j]=true;
		}
	}
	for(int i=2;i<=(n+1)/2;i++)
	if(!vis[i])ans.push_back(i);
	if(ans.empty())cout<<ans.size()<<endl;
	else 
	{
		int size=ans.size()-1;
		if((ans[size]-1)*2==(n-1))size--;
		for(int i=size;i>=0;i--)
		ans.push_back(n+1-ans[i]);
		cout<<ans.size()<<endl;
		for(int i=0;i<ans.size();i++)
		if(i!=ans.size()-1)printf("%d ",ans[i]);
		else printf("%d",ans[i]);
	}
	cout<<endl;
}
int main(void)
{
//	freopen("out.txt","w",stdout);
	while(~scanf("%d%lld",&n,&m))
	{
		solve();
	}
//	fclose(stdout);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值