10.2模拟赛总结

10.2 模拟赛总结

T1.

数位dp:

一个非常非常非常非常显然的数位 DP

\([L,R] = [1,R]-[1,L-1]\)

所以是分别求两次小于等于某个数字的方案数

\(f(i,j,k)\) 表示从低位数起的第 \(i\) 位,按照规则计算后答案为 \(j\quad (j=0,1)\)

\(k\) 表示只考虑后面结尾和 \(lmt\)后面几位 的大小关系 \((k=0,1)\)

考虑第 \(i+1\) 位,算一下新构成的数字并判断下大小就可以了

注意到 \(L,R\) 数据范围特别大,需要用高精度,最后结果要以二进制输出,所以可以对高精度压位

(以上扒的题解)

这题是个正常人就会想到找规律:

然后就有打表:(1~100)

然后就没了(啥?还有高精呢)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define LL long long
using namespace std;
int n, q, v,  t, L, R, len;
char s[208];
struct bigint
{
    int len, zz;
    int v[1005];
    bigint(){len = 0; memset(v, 0, sizeof v); zz = 1;}
    bigint(int x)
    {
        if(x >= 0) zz = 1;
        else x = -x, zz = 0;
        len = 0;
        memset(v, 0, sizeof v);
        while(x)
        {
            v[ ++len] = x % 10;
            x /= 10;
        }
    }
    friend bool operator < (const bigint &a, const bigint &b)
    {
        if(a.len < b.len) return 1;
        if(a.len > b.len) return 0;
        for(int i = a.len ; i >= 1; i -- )
        {
            if(a.v[i] < b.v[i]) return 1;
            if(a.v[i] > b.v[i]) return 0;
        }
        return 0;
    }
    friend bool operator == (const bigint &a, const bigint &b)
    {
        if(a.len != b.len ) return 0;
        for(int i = a.len; i >= 1; i --)
        {
            if(a.v[i] != b.v[i]) return 0;
        }
        return 1;
    }
    friend bool operator <= (const bigint &a, const bigint &b)
    {
        if(a < b) return 1;
        else if(a == b) return 1;
        else return 0;
    }
    friend bool operator != (const bigint &a, const bigint &b)
    {
        if(a.len != b.len) return 1;
        for(int i = a.len; i >= 1; i --)
        {
            if(a.v[i] != b.v[i]) return 1;
        }
        return 0;
    }
}x, y, res;
bigint operator + (bigint a, bigint b)
{
    int len = a.len + b.len;
    bigint c;
    c.len = len;
    for(int i = 1; i <= len; i ++)
     c.v[i] = a.v[i] + b.v[i];
    for(int i = 1; i <= len; i ++)
    {
        if(c.v[i] >= 10)
        {
            ++c.v[i+1];
            c.v[i] -= 10;
        }
    }
    while(c.len&&!c.v[c.len]) c.len --;
    return c;
}
bigint operator - (bigint a, bigint b)
{
    int len = max(a.len, b.len);
    bigint c;
    for(int i = 1; i <= len; i ++)
    c.v[i] = a.v[i] - b.v[i];
    c.len = len;
    for(int i = 1; i <= c.len; i ++)
    {
        if(c.v[i] < 0)
        {
            c.v[i+1]--;
            c.v[i] += 10;
        }
    }
    while(c.len&&!c.v[c.len]) c.len --;
    return c;
}
bigint operator *(bigint a,bigint b)
{
    bigint c;
    for(int i = 1; i <= a.len; ++ i)
    for(int j = 1; j <= b.len; ++ j)
    c.v[i+j-1] += a.v[i] * b.v[j];
    c.len = a.len + b.len;
    for(int i = 1;  i <= c.len - 1; ++ i)
    {
        if(c.v[i] >= 10)
        {
            c.v[i+1] += c.v[i] / 10;
            c.v[i] %= 10;
        }
    }
    while(c.v[c.len] == 0&&c.len > 1) -- c.len;
    return c;
}
bigint operator /(bigint a,long long b)
{
    bigint c;int d = 0;
    for(int i = a.len; i >= 1; -- i)
    c.v[++ c.len] = ((d * 10 + a.v[i]) / b),d=(d*10+a.v[i])%b;
    for(int i=1;i<=c.len/2;++i)swap(c.v[i],c.v[c.len-i+1]);
    while(c.v[c.len]==0&&c.len>1)--c.len;
    return c;
}
bigint Min(bigint a, bigint b)
{
    if(a < b) return a;
    else return b;
}
bigint work(bigint x)
{
    if(x < bigint(4)) return bigint(1);
    bigint l = bigint(4), r = Min(x, bigint(7)), res = bigint(1);
    int opt = 1;
    for(; ; l = r + bigint(1), r = Min(r * bigint(2)  + bigint(1), x), opt ^= 1 )
    {
        if(opt)
          res = res + (r - l + bigint(1));
          if(r == x) break;
    }
    return res;
}
void out(bigint x)
{
    if(!x.len) return (void)printf("0");
    bigint qwq = bigint(1);
    while(qwq <= x) qwq = qwq * bigint(2);
    qwq = qwq / 2;
    for(; ; qwq = qwq /2)
    {
        if(qwq <= x)
        {
            printf("1");
            x = x - qwq;
        }
        else printf("0");
        if(qwq == bigint(1))break;
    }
}
void solve()
{
    x = y = res = bigint(0);
    scanf("%s", s + 1);
    for(int i = 1; i <= n; i ++)
    {
        x = x * 2 + bigint(s[i] - '0');
    }
    scanf("%s", s + 1);
    for(int i = 1; i <= n; i ++)
    {
        y = y * 2 + bigint(s[i] - '0');
    }
    res = work(y) - work(x - bigint(1));
    if((n&1) == (q&1)) res = y - x + 1 - res;
    out(res);
    puts("");
}
signed main()
{
//  freopen("a.in", "r", stdin);
//  freopen("a.out", "w", stdout);
    scanf("%d", &t);
    while(t --)
    {
        scanf("%d%d",&n, &q);
        solve();
    }
    return 0;
}

T2

一sb题, 没啥总结的。。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define LL long long
#define N 100005
using namespace std;
struct node
{
    int w1, w2, l1, l2;
}q[N];
int n, m, t, minw = 2e9, maxw = -233, minl = 2e9, maxl = -233, flag;
signed main()
{
    freopen("b.in", "r",stdin);
    freopen("b.out", "w", stdout);
    scanf("%d", &t);
    while(t -- )
    {
        flag = 0; minw = minl = 2e9; maxw = maxl = -233;
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)
            scanf("%d%d%d%d", &q[i].w1, &q[i].w2, &q[i].l1, &q[i].l2);
        for(int i = 1; i <= n; i ++)
        {
            minw = min(minw, q[i].w1);
            maxw = max(maxw, q[i].w2);
            minl = min(minl, q[i].l1);
            maxl = max(maxl, q[i].l2);
        }
        for(int i = 1; i <= n; i ++)
        {
            if(q[i].w1 <= minw&&q[i].w2 >= maxw&&q[i].l1 <= minl&&q[i].l2 >= maxl)
            {flag = 1; break; }
        }
        if(flag)printf("TAK\n");
             else printf("NIE\n");
    }
    return 0;
}

T3

毒瘤数据结构+数论题

--给定1, n, d, v 给序列所有满足\(gcd(x, n)=d\)的\(x\), 给\(a[x]+=v\);

就相当于\(a[x]+=v[gcd(x, n)==d]\)

然后就可以愉快的推式子了

\(\ \ \ \ v[\gcd(x,n) = d]\)

$ = v [\gcd(\frac{x}{d},\frac{n}{d})=1]$

$ = v\sum\limits_{k|\gcd(\frac{x}{d},\frac{n}{d})} \mu(k)$ (日常反演)

$ = v\sum\limits_{k|\frac{x}{d},k|\frac{n}{d}} \mu(k)$

\(=\sum\limits_{k|\frac{n}{d},kd|x} v\mu(k)\)

暴力做法显然是要枚举\(x\), 对于每一个\({k|\frac{n}{d}且kd|x}\), 都加上\(v\mu(k)\),

可以等价于

对于一个合法的\(k|\dfrac{n}{d}\), 则\(x =kd,2kd,3kd...\), 枚举\(k\), 把所有\(kd\), 的倍数都加上\(v\mu(k)\);

这样虽然\(O(1)\)查询, 但修改的复杂度太大

考虑均摊复杂度

我们开一个数组\(f\) 表示所有是\(i\), 的倍数的位置都加上\(f[i]\)

修改时只需找出合法的\(k\), 然后\(f[kd]+=v\mu(k)\), 省去了枚举\(kd\) 的倍数;

然后查询时 查询一个数\(i\) 时, 就成了\(\sum_{d|i}f(d)\)

则\(x\), 的前缀和就是

\(\sum\limits_{i=1}^x\sum\limits_{d|i} f(d)=\sum\limits_{d=1}^x f(d)\lfloor \frac{x}{d}\rfloor\)

然后就可以整除分块, 对与每一块需要求出那一块的\(f\)的和;单点修改区间求和树状数组可以维护;

时间复杂度$O(q\sqrt{l}\log l+ l \log l) $

可以撒花了

然后这个柿子的理解

\(\sum\limits_{i=1}^x\sum\limits_{d|i}1=\sum\limits_{d=1}^{x}\lfloor\frac{x}{d}\rfloor\)

1到x每一个数的所有约数的个数

就相当于枚举一个约数, 这个约数的倍数的个数, x以内d的倍数的个数就是\(\lfloor\frac{x}{d}\rfloor\);

原文地址:https://www.cnblogs.com/spbv587/p/11618615.html

时间: 2024-11-08 23:49:03

10.2模拟赛总结的相关文章

10.22 模拟赛

10.22 模拟赛 T1 染色 考虑每个连通块删成一棵树就好了. mmp场上就我路径压缩写炸.... #include<iostream> #define MAXN 200006 using namespace std; int n , m; int fa[MAXN] , siz[MAXN] , book[MAXN] , sz[MAXN]; int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int main() {

10.31 模拟赛

10.31 模拟赛 A LIS 考虑每个数字前从 $ m $ 降序构造到 $ a_i $ 即可. #include <iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<vector> using namespace std; #define MAXN 300006 int n , m , k; int A[MAXN]; vector<int&g

10.5模拟赛

这么多模拟赛都没整理,能整理一天算一天吧qaq T1题面 sol:应该不难吧,分别对横坐标和纵坐标取差的绝对值,易知:如果互质就可以看到,否则就不行.然后出题人很毒瘤要用unsigned long long. #include <cstdio> #include <algorithm> using namespace std; long long x1,y1,x2,y2,c1=0,c2=0; unsigned long long x,y; unsigned long long AB

10 01模拟赛订正

好吧,这是我第一次写模拟赛的订正,主要是有时间而且这次的题确实好... 第一题确实好,用的算法人人都会,就是看你能不能想到,我考只打了O(n^4)的暴力,最后还苦逼的MLE,爆零了... 暴力就不多说了...枚举两个点更新其他的点... 其实我考场上思考的是,能被标记的点都与其他的点有什么联系,可惜,除了模拟题目的做法,就不会了... 那让我们就认真地思考一发:我们设A(x1,x2),B(x2,c2),C(x3,c3)来更新D点,只有:有两个点横坐标相等,有两个点纵坐标相等,才可以更新出来一个新

2019.10.24模拟赛赛后总结

本文原创,如果有不到位的地方欢迎通过右下角的按钮私信我! A.Icow Player 题目描述 被无止境的农活压榨得筋疲力尽后,Farmer John打算用他在MP3播放器市场新买的iCow来听些音乐,放松一下.FJ的iCow里存了N(1 <= N <= 1,000)首曲子,按1..N依次编号.至于曲子播放的顺序,则是按一个Farmer John自己设计的算法来决定: * 第i首曲子有一个初始权值R_i(1 <= R_i <= 10,000). * 当一首曲子播放完毕,接下来播放的

10.1 模拟赛

由于算错了inf 又ak失败了 过于菜 T1 年轮蛋糕 loj 2758 题目大意: n个数构成的环 把这个环分成三段 使最小的最大 求这个最小段的和的最大值 思路: 可以想到二分 因为log方可以过 所以可以二分长度后lower_bound找断点 或者使用滑动窗口 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cma

10.27 模拟赛

这一次终极被吊打 甚至没进前十 T2 最后改错 T3 没写正解 T1 elim 题目大意: n 行 m 列的游戏棋盘,一行或一列上有连续 三个或更多的相同颜色的棋子时,这些棋子都被消除 当有多处可以被消除时,这些地方的棋子将同时被消除 求消除后的棋盘 思路: sb模拟 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cm

10.4 模拟赛

写在前面: 我发现我每一次写题解都是改题改不出来了QAQ 其实今天的题都还好啦. T1 可见点数 其实就是 luogu仪仗队 的数据扩大版,开个long long然后数组开大点就可以过了. T2 射击 这个题就很有意思了. 小W和他的东厂厂长叔叔去打窗户.... 其中两句话很有误导的含义,不少人都死在了这句话上面.[其实只有我 /滑稽 每秒只能彻底打破一扇窗户. 你不能要求他们叔侄两个打破不同的窗户获得的快乐值必须相同. 错误的贪心策略: 把所有的窗户按时间排序,时间相同按价值排序,然后模拟选择

17.2.10 NOIP模拟赛 藏妹子之处(excel)

藏妹子之处(excel) 问题描述: 今天CZY又找到了三个妹子,有着收藏爱好的他想要找三个地方将妹子们藏起来,将一片空地抽象成一个R行C列的表格,CZY要选出3个单元格.但要满足如下的两个条件: (1)任意两个单元格都不在同一行. (2)任意两个单元格都不在同一列. 选取格子存在一个花费,而这个花费是三个格子两两之间曼哈顿距离的和(如(x1,y1)和(x,y2)的曼哈顿距离为|x1-x2|+|y1-y2|).狗狗想知道的是,花费在minT到maxT之间的方案数有多少. 答案模100000000