给定n个数a1,a2····an,依次求出相邻两个数值和,将得到一个新数列,重复上述操作,最后结果将变为一个数,问这个数除以m的余数与那些数无关?例如n=3,m=2时,第一次得到a1+a2,a2+a3,在求和得到a1+2*a2+a3,它除以2的余数和a2无关。1=<n<=10^5, 2=<m<=10^9
思路分析 :
看一下 n 的范围是 10^5 , 在二项式定理中又有这个公式
所以很容易在 O(n)的时间内推出所有项的系数,但是越往后面推 ,数会越大,爆掉 long long ,因此我们得换个方法
对 m 用唯一分解定理,那么接下来判断一个数是不是 m 的倍数,只需要判断这个数分解出的所有项的指数是否都大于等于 m 的即可
!!! 在用到容器的时候,如果有循环读入,一定要记得清空,不然一直超时
!!! 这个题最后输出的地方也好坑呀... 一直PE
代码示例 :
#define ll long long const ll maxn = 1e6+5; const ll mod = 1e9+7; const double eps = 1e-9; const double pi = acos(-1.0); const ll inf = 0x3f3f3f3f; vector<ll>prime; ll e[1000], f[1000]; ll n, m; ll k = 0; void init(){ k = 0; prime.clear(); memset(f, 0, sizeof(f)); memset(e, 0, sizeof(e)); for(ll i = 2; i <= sqrt(m); i++){ if (m % i == 0){ prime.push_back(i); while(m % i == 0) { m /= i; e[k]++; } k++; } } if (m != 1) { prime.push_back(m); e[k]++; } //prllf("++++ %d ", e[0]); } void add(ll x, ll d){ for(ll i = 0; i < prime.size(); i++){ ll su = prime[i]; while (x%su == 0){ f[i] += d; x /= su; } } } bool check(){ for(ll i = 0; i < prime.size(); i++){ if (f[i] < e[i]) return false; } return true; } vector<ll>ans; int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); while(cin >> n >> m){ init(); n--; ans.clear(); for(ll i = 1; i < n; i++){ add(n-i+1, 1); add(i, -1); if (check()) ans.push_back(i+1); } printf("%d ", ans.size()); for(ll i = 0; i < ans.size(); i++){ printf("%lld%c", ans[i], i==ans.size()-1?' ':' '); } if (ans.size() == 0) printf(" "); } return 0; }