A. 简单的区间
设左右端点的指针是 (i),(j),中点左边的和为 (sumi),中点右边的和为 (sumj)。合法区间需要满足 (sumi+sumj−Max≡0(modk))。那么 (i) 一步步向左扩展,我们需要找到一个符合条件的 (sumj),我们只需要开桶维护即可,符合条件的 (sumj) 即是 (k−sumi+Max)
所以直接(CDQ)分治,注意细节
Code
/* cinput
4 2
4 4 7 2
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#define int long long
using namespace std;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
inline void write(register int x){
if(x < 0) x = ~x + 1, putchar('-');
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int ss = 1000005;
int a[ss], sum[ss];
int cnt[ss], stk[ss], top;
int n, m, k;
long long ans;
inline void solve(register int l, register int r){
if(l == r) return;
register int mid = l + r >> 1;
register int i = mid, j = mid + 1;
register int maxx = 0, sumi = 0, sumj = 0;
for(i = mid; i >= l; i--){
maxx = max(maxx, a[i]);
sumi = (sumi + a[i]) % k;
while(a[j] <= maxx && j <= r){
sumj = (sumj + a[j]) % k;
cnt[sumj]++;
stk[++top] = sumj;
j++;
}
ans += cnt[((k - sumi + maxx) % k + k) % k];
}
while(top) cnt[stk[top--]] = 0;
i = mid, j = mid + 1;
maxx = 0, sumi = 0, sumj = 0;
for(j = mid + 1; j <= r; j++){
maxx = max(maxx, a[j]);
sumj = (sumj + a[j]) % k;
while(a[i] < maxx && i >= l){
sumi = (sumi + a[i]) % k;
cnt[sumi]++;
stk[++top] = sumi;
i--;
}
ans += cnt[((k - sumj + maxx) % k + k) % k];
}
while(top) cnt[stk[top--]] = 0;
solve(l, mid);
solve(mid + 1, r);
}
signed main(){
freopen("interval.in", "r", stdin);
freopen("interval.out", "w", stdout);
n = read(), k = read();
for(register int i = 1; i <= n; i++) a[i] = read();
solve(1, n);
printf("%lld
", ans);
return 0;
}
B. 简单的玄学
考场出式子取(mod)取多了
(50 ->10)
(1-cfrac{(2^n)^{underline m}}{2^{nm}}=1-cfrac{prodlimits_{i=2^n-m+1}^{2^n-1}i}{2^{n(m-1)}})
注意到模数很小,所以可以在这上面下手。所以我们发现当 (m>10^6+3) 的时候,取模一定是 (0) 了,直接 (break) 掉就行了。
再有,观察到分子分母上只有(2)是可以约分的,所以对于每个数字统计当中(2)的个数进行约分
有
对于任意一个 (1≤a<2n),(a) 与 (2n−a) 的中(2)的次数相同。
因此所以我们要求的就是 ((m−1)!)中因子 2 的个数(O(logm))
for(int i=2;i<=m;i<<=1)
cnt+=m/i;
注意一点,最后一起乘上2出现次数的次方的逆元
不然会炸范围
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define int long long
using namespace std;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
inline void write(register int x){
if(x < 0) x = ~x + 1, putchar('-');
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int mod = 1e6 + 3;
const int inv2 = 500002;
inline int power(register int a, register int b){
register int ans = 1;
while(b){
if(b & 1) ans = 1ll * ans * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
if(ans >= mod) ans %= mod;
return ans;
}
signed main(){
freopen("random.in", "r", stdin);
freopen("random.out", "w", stdout);
register int n = read(), m = read();
if((double) log2(m) - (double) n > 1e-6) return puts("1 1"), 0;
register int a = 1, p = power(2, n), b = power(p, m);
for(register int i = 1; i <= m; i++){
a = a * (p - i + 1) % mod;
if(!a) break;
}
register int cnt = n;
m--;
for(register int i = 2; i <= m; i <<= 1)
cnt += m / i;
a = a * power(inv2, cnt) % mod;
b = b * power(inv2, cnt) % mod;
printf("%lld %lld
", (b - a + mod) % mod, b);
return 0;
}
C. 简单的填数
D. 聪聪和可可
乍一看以为是(CDQ)分治的板子题
结果是聪聪和可可
然后我就不会了
(xjbYY)了个暴搜然后段错误
然后(rand)完就扔了
考完原来
记忆化搜索就可,,,
Code
/* cinput
9 9
9 3
1 2
2 3
3 4
4 5
3 6
4 6
4 7
7 8
8 9
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#define int long long
using namespace std;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
inline void write(register int x){
if(x < 0) x = ~x + 1, putchar('-');
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int ss = 1010;
struct node{
int to, nxt;
}edge[ss << 1];
int head[ss], tot;
inline void add(register int u, register int v){
edge[++tot].to = v;
edge[tot].nxt = head[u];
head[u] = tot;
}
queue<int> q;
int dis[ss][ss], p[ss][ss];
inline void bfs(register int s){
q.push(s);
while(!q.empty()){
register int u = q.front();
q.pop();
register int tmp = p[s][u];
for(register int i = head[u]; i; i = edge[i].nxt){
register int v = edge[i].to;
if(dis[s][v] == -1 || (dis[s][u] + 1 == dis[s][v] && tmp < p[s][v])){
dis[s][v] = dis[s][u] + 1;
p[s][v] = tmp ? tmp : v;
q.push(v);
}
}
}
}
double f[ss][ss], deg[ss];
inline double dfs(register int cc, register int kk){
if(cc == kk) return 0;
if(p[cc][kk] == kk || p[p[cc][kk]][kk] == kk) return f[cc][kk] = 1.0;
if(f[cc][kk]) return f[cc][kk];
register double sum = dfs(p[p[cc][kk]][kk], kk);
for(register int i = head[kk]; i; i = edge[i].nxt){
register int v = edge[i].to;
sum += dfs(p[p[cc][kk]][kk], v);
}
return f[cc][kk] = 1.0 * sum / (deg[kk] + 1) + 1;
}
main(){
freopen("cchkk.in", "r", stdin);
freopen("cchkk.out", "w", stdout);
register int n = read(), m = read(), c = read(), k = read();
memset(dis, -1, sizeof dis);
for(register int i = 1; i <= m; i++){
register int u = read(), v = read();
add(u, v);
add(v, u);
deg[u]++;
deg[v]++;
}
for(register int i = 1; i <= n; i++) bfs(i);
printf("%.3lf
", dfs(c, k));
return 0;
}