• 9.18 校内模拟赛 题解报告


    9.18 校内模拟赛 题解报告

    T1 sb dp

    T2 sb 数论

    T3 分析 + 数据结构

    BS: 做不出 sb 题的 sb

    大概这场考试就是这样...


    关于考试过程以及一些题外话

    传说中的送分题 拿不到分系列

    T1 一开始的时候先看到前面 (O(2^n)) 的暴力 再看数据以为是个结论题 然后感觉好像可以直接 dp 复杂度 (O(n)) 好像能过 稍微卡了一下 感觉没什么问题就扔了

    T2 ...

    BS: 我曾尝试做过

    T3 最开始想到的是回滚莫队... 然后看到区间和就没辙了 类比回滚算贡献的方法把 (O(n^2)) 的部分写了就滚粗了

    最后补了一个 T2 的 (O(R - L)) 的暴力


    这个 T3 真的满脑子回滚莫队 根本没发现单调性


    得分情况

    100 + 30 + 48 = 178

    所以这个 (48) 是个啥...


    题解

    显然没有题解

    T1 zero

    状态: (f_{i, 0/1}) 表示前 (i) 位置运算得到 (0/1) 的方案数

    转移考虑当前位选择的数造成的运算结果


    代码

    /*
      Source:
    */
    #include<cstdio>
    #include<cstring>
    #define int long long
    #define pt putchar(' ')
    #define pn putchar('
    ')
    /*----------------------------------------------------------*/
    const int A = 1e4 + 7;
    const int B = 1e5 + 7;
    const int C = 1e6 + 7;
    const int D = 1e7 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    /*----------------------------------------------------------*/
    template <typename T> inline T Pow(T x) {return x * x;}
    template <typename T> inline T Abs(T x) {return x < 0 ? -x : x;}
    template <typename T> inline T Min(T x, T y) {return x < y ? x : y;}
    template <typename T> inline T Max(T x, T y) {return x > y ? x : y;}
    template <typename T> inline void Swap(T x, T y) {x ^= y ^= x ^= y;}
    /*----------------------------------------------------------*/
    inline void File() {
    	freopen("zero.in", "r", stdin);
    	freopen("zero.out", "w", stdout);
    }
    /*----------------------------------------------------------*/
    int n, f[D][2], pa[25], ans;
    char s[D];
    /*----------------------------------------------------------*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
    /*----------------------------------------------------------*/
    bool check() {
    	int res = pa[0];
    	for(int i = 1; i ^ n + 1; ++i)
    		if(s[i] == '&') res &= pa[i];
    		else if(s[i] == '|') res |= pa[i];
    		else if(s[i] == '^') res ^= pa[i];
    	return res;
    }
    void print() {
    	for(int i = 0; i ^ n + 1; ++i) Print(pa[i]), pt; pn;
    }
    void dfs1(int t) {
    	if(t == n + 1) {if(check()) ans++; return ;}
    	pa[t] = 0; dfs1(t + 1); pa[t] = 1; dfs1(t + 1);
    }
    void work1() {dfs1(0); Print(ans);}
    void work2() {
    	f[1][0] = f[1][1] = 1;
    	for(int i = 1; i ^ n + 2; ++i)
    		if(s[i] == '&') f[i + 1][0] = (f[i + 1][0] + f[i][0] + f[i][1] + f[i][0]) % mod, f[i + 1][1] = (f[i + 1][1] + f[i][1]) % mod;
    		else if(s[i] == '|') f[i + 1][0] = (f[i + 1][0] + f[i][0]) % mod, f[i + 1][1] = (f[i + 1][1] + f[i][0] + f[i][1] + f[i][1]) % mod;
    		else if(s[i] == '^') f[i + 1][0] = (f[i + 1][0] + f[i][0] + f[i][1]) % mod, f[i + 1][1] = (f[i + 1][1] + f[i][0] + f[i][1]) % mod;
    	Print(f[n + 1][1] % mod);
    }
    void Main() {
    	File();
    //	freopen("a.in", "r", stdin);
    	n = read(); scanf("%s", s + 1);
    //	if(n <= 20) work1();
    //	else work2();
    	work2();
    }
    /*----------------------------------------------------------*/
    signed main() {Main(); return 0;}
    
    

    T2 prime

    题目要求:

    [sum_{y = L}^R [gcd(y - k, y + k) = 1] ]

    首先 有:

    [gcd(a, b) = gcd(b, a - b) ]

    考虑题中原式取值进行转化 设 (i = y - k) 有:

    [sum_{i = L}^{R - 2k} [gcd(i, 2k) = 1] ]

    这个式子的含义就是求 ([L, R - 2k]) 中与 (2k) 互质的数的个数 考虑将所有与 (2k) 不互质的数筛掉

    (2k) 进行质因数分解 取出其所有质因数 然后将 ([L, R - 2k]) 范围内还有这些质因数的数都筛掉

    对于每个质因数考虑取与不取两种情况 由于 (k) 只有 (10^{13}) 所以其质因数不会超过 (15)

    对于区间中会被具有多个 (2k) 的质因子的数筛去 容斥一下即可


    代码

    /*
      Source: 小y的质数
    */
    #include<cstdio>
    #define int long long
    /*----------------------------------------------------------*/
    int L, R, K, p[20], cnt, ans;
    /*----------------------------------------------------------*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
    /*----------------------------------------------------------*/
    void pre(int x) {
    	for(int i = 2; i * i <= x; ++i) if(!(x % i))
    	{
    		p[++cnt] = i;
    		while(!(x % i)) x /= i;
    	}
    	if(x > 1) p[++cnt] = x;
    }
    void dfs(int t, int x, int sum) {
    	if(t == cnt + 1) {int k = sum & 1 ? 1 : -1; if(sum) ans += k * (R / x - (L - 1) / x); return ;}
    	dfs(t + 1, x, sum); dfs(t + 1, x * p[t], sum + 1);
    }
    void Main() {
    	L = read(); R = read(); K = read() << 1; R -= K;
    	if(R < L) {Print(0); return ;} if(!L) ++L;
    	pre(K); dfs(1, 1, 0); Print(R - L + 1 - ans);
    }
    /*----------------------------------------------------------*/
    signed main() {Main(); return 0;}
    
    

    T3 mex

    如果确定某一点作为区间的左端点 将区间向右侧延伸 则随着区间的延伸 区间的 (mex) 是单调上升的

    首先求出所有以 (1) 作为左端点的区间的 (mex) 此时求和即为所有以 (1) 为左端点区间的贡献 而如果将 (a_1) 的贡献去除 得到的就是所有以 (2) 作为左端点的区间的贡献总和

    考虑如何去除 (a_1) 的贡献 将所有区间的左端点转移到 (2)(a_1 = x) 若是将 (a_1) 删去 一定不会影响到下一个包含与 (a_1) 相等数的位置 不妨设 (1) 之后第一个与 (a_1) 相等的位置为 (pos) 则删除 (a_1) 一定不会影响右端点在 ([pos, n]) 的区间(左端点在 (2)) 再考虑对区间 ([2, pos - 1]) 的影响 现在已经维护出了所有以 (1) 为左端点的区间 这些区间的 (mex) 值是单调递增的 在这些 (mex) 值中 会被影响到的只有大于 (a_1) 的值 只需要将所有的这些值直接改为 (a_1) 就好了 这时维护的就是以 (2) 作为区间左端点的所有区间 求和计入答案

    按照上面的方法 将所有数逐个删除 维护删除后区间的 (mex) 和 求和为答案

    总结一下的话

    一开始将以 (1) 为区间左端点的区间的 (mex) 值求出来 直接对应到下标 如 ([1, 3] o 3, [1, 1] o 1) 这样需要维护的东西就是区间求和 区间赋值 查询区间中大于某个数的值 这些操作显然是都可以在线段树上维护的


    代码

    /*
      Source: mex
    */
    #include<cstdio>
    #define int long long
    /*----------------------------------------------------------*/
    const int B = 1e5 + 7;
    const int INF = 0x3f3f3f3f;
    /*----------------------------------------------------------*/
    template <typename T> inline T Min(T x, T y) {return x < y ? x : y;}
    template <typename T> inline T Max(T x, T y) {return x > y ? x : y;}
    /*----------------------------------------------------------*/
    int n, a[B], mex[B], cnt[B], K, pos[B], pre[B], ans;
    /*----------------------------------------------------------*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
    /*----------------------------------------------------------*/
    namespace Seg {
    	#define ls(x) x << 1
    	#define rs(x) x << 1 | 1
    	#define len (t[p].r - t[p].l + 1)
    	#define mid (t[p].l + t[p].r >> 1)
    	struct node {
    		int l, r, sum, max, lzy;
    		node() {l = r = sum = max = 0; lzy = -1;}
    	} t[B << 2];
    	void push_up(int p) {t[p].sum = t[ls(p)].sum + t[rs(p)].sum; t[p].max = Max(t[ls(p)].max, t[rs(p)].max);}
    	void build(int p, int l, int r) {
    		t[p].l = l; t[p].r = r; if(l == r) {t[p].sum = t[p].max = mex[l]; return ;}
    		build(ls(p), l, mid); build(rs(p), mid + 1, r); push_up(p);
    	}
    	void f(int p, int k) {t[p].lzy = t[p].max = k; t[p].sum = k * len;}
    	void push_down(int p) {f(ls(p), t[p].lzy); f(rs(p), t[p].lzy); t[p].lzy = -1;}
    	void up_date(int p, int l, int r, int k) {
    		if(l <= t[p].l && t[p].r <= r) {f(p, k); return ;}
    		if(~t[p].lzy) push_down(p);
    		if(l <= mid) up_date(ls(p), l, r, k); if(r > mid) up_date(rs(p), l, r, k);
    		push_up(p);
    	}
    	int query(int p, int k) {
    		if(t[p].l == t[p].r) return t[p].l;
    		if(k < t[ls(p)].max) return query(ls(p), k); else return query(rs(p), k);
    	}
    }
    void Main() {
    	n = read(); mex[n + 1] = INF; pre[0] = n + 1;
    	for(int i = 1; i ^ n + 1; ++i) a[i] = read(), cnt[a[i]]++, pre[i] = n + 1;
    	for(int i = 0; i ^ n + 1; ++i) if(!cnt[i]) {K = i; break;}
    	for(int i = n; i; --i)
    	{
    		mex[i] = K; if(!--cnt[a[i]]) K = Min(K, a[i]);
    		pos[i] = pre[a[i]]; pre[a[i]] = i;
    	}
    	Seg::build(1, 1, n); ans = Seg::t[1].sum;
    	for(int i = 1; i ^ n + 1; ++i)
    	{
    		Seg::up_date(1, i, i, 0);
    		if(Seg::t[1].max > a[i])
    		{
    			int x = Seg::query(1, a[i]);
    			if(x < pos[i]) Seg::up_date(1, x, pos[i] - 1, a[i]);
    		}
    		ans += Seg::t[1].sum;
    	}
    	Print(ans);
    }
    /*----------------------------------------------------------*/
    signed main() {Main(); return 0;}
    
  • 相关阅读:
    MacOS Sierra允许运行任何来源的程序
    Windows Server2008 R2中的角色
    Linux根目录解析
    Linux安装配置SVN服务器
    Linux6.x修改出eth0网卡的解决方法
    如何利用mount命令挂载另一台服务器上的目录
    Arcgis水文分析-Dem提取集水区
    前端布局之Flex布局
    其实我就是想好好的写写代码(一个伪程序猿的独白)
    WebApi关于配置全局返回Json数据格式时间以及命名小写
  • 原文地址:https://www.cnblogs.com/blank-space-/p/15310266.html
Copyright © 2020-2023  润新知