Loading

联赛模拟测试17(T3 简单的填数未补)

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\n", ans);
	return 0;
}

B. 简单的玄学

考场出式子取\(mod\)取多了
\(50 ->10\)
\(1-\cfrac{(2^n)^{\underline m}}{2^{nm}}=1-\cfrac{\prod\limits_{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\n", (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\n", dfs(c, k));
	return 0;
}
posted @ 2020-10-15 13:57  Gary_818  阅读(20)  评论(0编辑  收藏