杭电2021第十次

1003:
签到提,有两种思路可以做这个题
第一个思路是从前往后递推,我们可以去枚举当前有 \(i\) 条线是平行的,然后剩下的 \(n - i\) 条线有不同的情况,但是已经在前面推出来了,可以存在一个容器中,那么交点数的可能就是 \(i * (n - i) + v[n - i][j](1 <= i <= n, 0 <= j <= v[n - i].size()\),复杂度是\(n^4\)的,过不了,可以通过 bitset 优化,相当于用bitset 作为容器,那么就将 一维\(n^2\) 的复杂度用位运算优化了,时间复杂度仍有 \(3e9\) ,可以发现后面都是一段很长的连续,那么对于后面连续的只要全部输出就可以了,那么可以考虑打前面的表观察加上人工二分,在T和wa之间寻找AC,最后可以得到 \(32000\) 是比较优的,所以复杂度 \(\frac {{700}^2 * 32000 + T * 32000} w\),可以过这个题。
第二个思路就是 \(n\) 条线的时候可能的点数就是 \(\frac {n * (n - 1)} 2 - \sum_{x_i} \frac {x_i * (x_i - 1)} 2, \sum_{x_i} = n\),就是枚举所有直线平行的情况,对于某个斜率,有 \(k\) 条直线平行,那么答案就会少 \(k * (k - 1) / 2\),我们可以在递推过程中用一个 \(f_i\) 保存下来得到 \(\sum frac {x_i * (x_i - 1)} 2\) 的最小 \(n\) 值,那么对于大于这个值的同样可以取到这个值,那么求n的答案就是求 \(f_i <= n\) 的情况。复杂度的 \({700}^3 + T * n^2\)
bitset没怎么用过,所以没想到这个,每个数都加上同样的数,刚好契合。

const int maxn = 7e2 + 10;
const int N = 32000;
bitset<N> bt[maxn];
bool vis[maxn * maxn];

void init() {
    bt[1][0] = 1;
    for(int i = 2; i <= 700; ++ i) {
        bt[i][0] = 1;
        for(int j = i - 1; j >= 1; -- j) {
            bt[i] |= bt[j] << (j * (i - j));
        }
        //cout << bt[i] << endl;
    }
}

void run() {
    int n; scanf("%d", &n);
    int sz = n * (n - 1) / 2, up = N;   printf("0");
    for(int i = 1; i < up; ++ i)
        if(bt[n][i])    printf(" %d", i);
    for(int i = up; i <= sz; ++ i)    printf(" %d", i);
    puts("");
}

int f[maxn * maxn];
vector<int> qur[701];
vector<int> ans[6];
void init2() {
    memset(f, 0x3f, sizeof f);  f[0] = 0;
    int M = maxn * maxn / 2;
    for(int i = 1; i <= 700; ++ i) {
        for(int j = 0; j < M; ++ j) {
            int k = j + i * (i - 1) / 2;
            if(k < M)   f[k] = min(f[k], f[j] + i);
        }

        for(auto it : qur[i]) {
            int up = i * (i - 1) / 2;
            for(int j = up; j >= 0; -- j) {
                if(f[j] <= i)   ans[it].push_back(up - j);
            }
        }
    }
    for(int i = 0; i < 5; ++ i) if(ans[i].size())
        for(int j = 0; j < ans[i].size(); ++ j)
            printf("%d%c", ans[i][j], " \n"[j == ans[i].size() - 1]);
}

signed main() {
    int t = 1, x;
    //init1();
    scanf("%d", &t);
    for(int i = 0; i < t; ++ i) scanf("%d", &x),   qur[x].push_back(i);
    init2();
    //run();
    return 0;
}

1004:一道暴力优化的题目
k个素数直接求容斥的复杂度是枚举子集 \(2^k\),对于 \(T = 1e5\) 不行,想一想就可以想到是不是分块来做,但是当时想不出来怎么搞,因为确实可以对前面的部分素数求 \(lcm\) 来根据 \(lcm\) 分块,但是后面的素数没法处理,每块中这些是不同的。
没想到的就是对于每个整除,可以把除数分为两部分,一部分是前8个,一部分是后8个,那么容斥的过程,我们只要枚举后八个的情况,\(n\) 除掉每个后8个素数的子集后得到的就是只剩下前八个素数的块了,这个可以分块预处理,那么复杂度就变成了 \(T * 2^8\)
也就是对前八个素数预处理,对后8个素数容斥。

const int N = 1 << 8;
const int M = 9699690;
const int FM = 1658880;
int pri[20] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
struct node{
    ll a[N], b[N];
    int a0, b0;
}a[17];
int f[M + 1];

void init() {
    for(int i = 1; i <= 16; ++ i) {
        a[i].a[++ a[i].a0] = pri[i];
        if(i == 1 || i == 9)    continue;
        for(int j = 1; j <= a[i - 1].a0; ++ j) {
            a[i].a[++ a[i].a0] = a[i - 1].a[j];
            a[i].b[++ a[i].b0] = a[i - 1].a[j] * pri[i];
        }
        for(int j = 1; j <= a[i - 1].b0; ++ j) {
            a[i].b[++ a[i].b0] = a[i - 1].b[j];
            a[i].a[++ a[i].a0] = a[i - 1].b[j] * pri[i];
        }
    }

    for(int i = 1; i <= 8; ++ i)
        for(int j = pri[i]; j <= M; j += pri[i])    f[j] = 1;
    for(int i = 1; i <= M; ++ i)    f[i] = (!f[i]) + f[i - 1];
    //cout << f[M] << endl;
    return ;
}

void run() {
    ll n, k; scanf("%lld %lld", &n, &k);
    ll res = 0;
    if(k <= 8) {
        res = n;
        for(int i = 1; i <= a[k].a0; ++ i)  res -= n / a[k].a[i];
        for(int i = 1; i <= a[k].b0; ++ i)  res += n / a[k].b[i];
        printf("%lld\n", res);
    }
    else {
        res += (n / M) * FM + f[n % M];
        for(int i = 1; i <= a[k].a0; ++ i) {
            ll t = n / a[k].a[i];
            res -= (t / M) * FM + f[t % M];
        }
        for(int i = 1; i <= a[k].b0; ++ i) {
            ll t = n / a[k].b[i];
            res += (t / M) * FM + f[t % M];
        }
        printf("%lld\n", res);
    }
    return ;
}
posted @ 2021-08-20 15:38  wlhp  阅读(7)  评论(0)    收藏  举报