signedmain(){ ios::sync_with_stdio(false), cin.tie(0); int l, r, x, y; while (cin >> l >> r >> x >> y) { if (y % x != 0) { //特判:不能整除说明肯定不存在 cout << 0 << endl; continue; } int ret = y / x; int cnt = 0; int tot1 = r / x; //右边界1 int tot2 = sqrt(ret); //右边界2 for (int i = ceil(l * 1.0 / x); i <= tot1 && i <= tot2; ++i) { if (ret % i == 0 && __gcd(ret / i, i) == 1 && ret / i <= tot1) { //判断另一个因数是否在范围内并且互质 if (ret / i == i) ++cnt; //拆除的因数相同只能形成一对 else cnt += 2; } } cout << cnt << endl; } // system("pause"); return0; }
ll quick_pow(ll a, ll b){ ll ans = 1, base = a; while (b) { if (b & 1) ans = ans * base % mod; base = base * base % mod; b >>= 1; } return ans % mod; }
signedmain(){ ios::sync_with_stdio(false), cin.tie(0); ll x, k; while (cin >> x >> k) { if (x == 0) { cout << 0 << endl; continue; } ll ans = (x % mod) * quick_pow(2, k + 1); ans = ((ans - quick_pow(2, k) + mod) % mod + 1) % mod; //因为是取模后相减有可能2^k+1比2^k小,防止取到负数 cout << ans << endl; } // system("pause"); return0; }
题意:有一个大小为 n 的数组 a,请确定它有多少个子区间满足子区间内数的乘积是区间内数的加和的 k 倍( 1<=n<=2e5,1<=k<=1e5,1<=a[i]<=1e8)
思路: 参考博客 这题难在数据范围太大了,考虑区间 dp 但是根本开不了那么大的数组也不会转移方程。乘积实际上是有限制的,最大是 2e5*1e5*1e8=2e18 在 long long 范围内,再大的乘积肯定不满足题意了,而 long long 是 264,也就是说最多由 64 个非 1 的数相乘得到(数据量已经很小了可以暴力判断),综上我们在考虑特殊的数组中 1 就可以了
voidinit(){ nex[n + 1] = n + 1; //处理边界 for (int i = n; i >= 1; --i) { if (a[i] == 1) nex[i] = nex[i + 1]; else nex[i] = i; } }
booloverflow(ll x, ll y){ //判断乘积是否会溢出long long return x > LLONG_MAX / y; }
ll cal(int pos){ int cnt = 0; ll pro = a[pos], sum = a[pos]; if (k == 1) ++cnt; //特判k=1情况需要算上自己 for (int j = pos + 1; j <= n; ++j) { //枚举右端点 if (overflow(pro, a[j])) return cnt; //先判断是否溢出,溢出后面肯定没有答案返回 if (a[j] == 1) { //看其后面连续的1区间中是否满足条件的唯一的区间 int ret = nex[j] - j; if (pro % k == 0 && (sum + 1) <= (pro / k) && (sum + ret) >= (pro / k)) //pro满足答案的区间和是否处于连续的1区间的范围中 ++cnt; sum += ret; //直接跳到不为1的下一个位置 j = nex[j] - 1; //这是个循环最后还会有个+1所以这里先跳到目标位置的前面一个位置 } else { pro *= a[j], sum += a[j]; if (pro % sum == 0 && pro / sum == k) //暴力判断区间是否满足条件 ++cnt; } } return cnt; }
signedmain(){ ios::sync_with_stdio(false), cin.tie(0); while (cin >> n >> k) { for (int i = 1; i <= n; ++i) cin >> a[i]; init(); //统计出下一个不为1的位置 ll ans = 0; for (int i = 1; i <= n; ++i) //统计以i为左端点的满足条件的区间个数 ans += cal(i); cout << ans << endl; } // system("pause"); return0; }