• 联赛模拟测试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
    ", 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;
    }
    
  • 相关阅读:
    JS文本框下拉提示效果
    JS动态添加删除表格行
    JS验证 数字 电话号码 传真 邮箱 手机号码 邮编 日期
    TreeView 中CheckBox级联选中问题
    HashTable Dictionary
    JS操作Frame对象
    Winfrom 中怎样在回车时设置焦点
    Word 操作(未完待续)
    HTML5特性——prefetching预加载功能
    10个实用的 jQuery Mobile 插件推荐
  • 原文地址:https://www.cnblogs.com/rui-4825/p/13820200.html
Copyright © 2020-2023  润新知