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);
}