11.22 模拟赛

A.#

将原式进一步化简可得 (n2)i=1naibi+i=1nai×sumb,令 suma=i=1nai,sumab=i=1naibi,则原式 =(n2)sumabsuma×sumb,显然 sumab,suma,sumb 都可以 O(1) 修改,那么该式子也可以 O(1) 修改。

时间复杂度:O(n+q)

哎赛事代码太丑了点。

代码 #include #define int __int128 using namespace std;
typedef unsigned long long ull;
const int N = 1e6 + 7;
int a[N], b[N];
int aa[N], bb[N], cc[N], c[N];
bool op[N];
int x[N], v[N];

int T1[N], T2[N], T3[N];
int n, q, V;
int lowbit(int x) {return x & (-x);}
int query1(int pos) {
    int res = 0;
    for(int i = pos; i; i -= lowbit(i)) res += T1[i];
    return res;
}
void modify1(int pos, int x) {
    for(int i = pos; i <= n; i += lowbit(i)) T1[i] += x;
}
int getsum1(int l, int r) {
    if(r < l) return 0;
    return query1(r) - query1(l - 1);
}
int query2(int pos) {
    int res = 0;
    for(int i = pos; i; i -= lowbit(i)) res += T2[i];
    return res;
}
void modify2(int pos, int x) {
    for(int i = pos; i <= n; i += lowbit(i)) T2[i] += x;
}
int getsum2(int l, int r) {
    if(r < l) return 0;
    return query2(r) - query2(l - 1);
}
int query3(int pos) {
    int res = 0;
    for(int i = pos; i; i -= lowbit(i)) res += T3[i];
    return res;
}
void modify3(int pos, int x) {
    for(int i = pos; i <= n; i += lowbit(i)) T3[i] += x;
}
int getsum3(int l, int r) {
    if(r < l) return 0;
    return query3(r) - query3(l - 1);
}
void gen(int n,int q,int V,ull seed){
    std::mt19937_64 rnd(seed);
    for(int i = 1; i <= n; i ++) a[i] = rnd() % (V + 1);
    for(int i = 1; i <= n; i ++) b[i] = rnd() % (V + 1);
    for(int i = 1; i <= q; i ++) op[i] = rnd() & 1, x[i] = rnd() % n + 1, v[i] = rnd() % (V + 1);
}
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*10+ch-'0',ch=getchar();
    return x*f;
}
void write(int x)
{
    if(x<0)
        putchar('-'),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
    return;
}
signed main() {
    freopen("calculate.in", "r", stdin);
    freopen("calculate.out", "w", stdout);
    ull seed;
    n = read(), q = read(), V = read(), seed = read();
    gen(n, q, V, seed);
    // int n;
    // cin >> n;
    // for(int i = 1; i <= n; i ++) cin >> a[i];
    // for(int i = 1; i <= n; i ++) cin >> b[i];
    for(int i = 1; i <= n; i ++) {
        modify1(i, a[i]);
        modify2(i, b[i]);
        modify3(i, a[i] * b[i]);
    }
    // cout << t1.query(n);
    // for(int i = 1; i <= n; i ++) cout << a[i] << " ";
    // cout << endl;
    // for(int i = 1; i <= n; i ++) cout << b[i] << " ";
    // cout << endl;
    // int ans = 0;
    // for(int i = 1; i <= n - 1; i ++) for(int j = i + 1; j <= n; j ++) ans += (a[i] - a[j]) * (b[i] - b[j]);
    // cout << ans << endl;

    int ans1 = 0, ans2 = 0;
    for(int i = 1; i <= n; i ++) ans1 += (n - i) * a[i] * b[i];
    for(int i = 1; i <= n; i ++) ans1 -= (a[i] * getsum2(i + 1, n) + b[i] * getsum1(i + 1, n) - getsum3(i + 1, n));
    write(ans1);
    puts("");
    for(int i = 1; i <= q; i ++) {
        if(op[i] == 0) {
            ans1 -= (n - x[i]) * a[x[i]] * b[x[i]];
            ans1 += (n - x[i]) * v[i] * b[x[i]];

            int p = v[i] - a[x[i]];
            int now = getsum2(1, x[i] - 1) * p;
            ans1 -= now;
            int p2 = v[i] * b[x[i]] - a[x[i]] * b[x[i]];
            ans1 += (x[i] - 1) * p2;    
            ans1 -= getsum2(x[i] + 1, n) * p;
            write(ans1);
            puts("");
            modify1(x[i],  -a[x[i]]);
            modify1(x[i], v[i]);
            a[x[i]] = v[i];
        }
        else {
            ans1 -= (n - x[i]) * a[x[i]] * b[x[i]];
            ans1 += (n - x[i]) * v[i] * a[x[i]];
            int p = v[i] - b[x[i]];
            int now = getsum1(1, x[i] - 1) * p;
            ans1 -= now;
            int p2 = v[i] * a[x[i]] - a[x[i]] * b[x[i]];
            ans1 += (x[i] - 1) * p2;
            ans1 -= getsum1(x[i] + 1, n) * p;
            write(ans1);
            puts("");
            modify2(x[i],  -b[x[i]]);
            modify2(x[i], v[i]);
            b[x[i]] = v[i];
        }
    }
}
### B.

从小到大往里填数,dpi,j,s 表示第一组填了 i 个数,第二组填了 j 个数,当前填的后 k1 个数所在的组的状态集合为 s,下一个数即为 i+j+1

假设把第 i+j+1 个数放到第一组,若 i>=j,则没有影响,可以填入。若 i<j,则要看 |a1,i+1a2,i+1|k 是否成立,即为 a2,i+1 不能在最后 k1 个数里出现,直接数 S 有多少个 1 即可,因为 j 也是已知的,所以假如 Sl 个第二组的说明 a2,jl+1j 都在当前最大的 k1 个数中,直接看它包不包括 i+1 即可,这部分复杂度是 O(k)

代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 7;
int dp[201][201][1026];
int vis[201][201][1026];
int get(int s, int x) {
    int cnt = 0;
    while(s) {
        if(s % 2 == x) cnt ++;
        s >>= 1;
    }
    return cnt;
}
int n, k, mod;
int C[202][202];
void sol1() {
    for(int i = 0; i <= 2 * n; i ++) C[i][i] = C[i][0] = 1;
    for(int i = 1; i <= 2 * n; i ++) {
        for(int j = 1; j < i; j ++) {
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
        }
    }
    cout << C[2 * n][n] % mod;
}
signed main() {
    // 10000
    
    cin >> n >> k >> mod;
    if(k == 1) {
        sol1();
        return 0;
    }
    k --;
    int ss = (1 << k) - 1;
    dp[0][1][1] = 1;
    dp[1][0][0] = 1;
    for(int i = 0; i <= n; i ++) {
        for(int j = 0; j <= n; j ++) {
            int cnt = 0;
            for(int s = 0; s < (1 << k); s ++) {
                if(vis[i][j][s]) continue;
                // vis[i][j][s] = 1;
                int len = min(i + j, k);
                int sm1 = get(s, 1);
                int sm0 = len - sm1;
                // cout << "from: " << i << " " << j << " " << s << " " << sm0 << " " << sm1 << " " << dp[i][j][s] << endl;
                if(i > j) {
                    dp[i + 1][j][(s << 1) & ss] = (dp[i + 1][j][(s << 1) & ss] + dp[i][j][s]) % mod;
                    // cout << i + 1 << " " << j << " " << ((s << 1) & ss) << " " << dp[i + 1][j][(s << 1) & ss] << "\n";
                    if(sm0 >= i - j) continue;
                    dp[i][j + 1][((s << 1) & ss) | 1] = (dp[i][j + 1][((s << 1) & ss) | 1] + dp[i][j][s]) % mod;
                    // cout << i << " " << j + 1 << " " << ((s << 1) & ss | 1) << " " << dp[i][j + 1][(s << 1) & ss | 1] << "\n";
                }
                else if(j > i) {
                    dp[i][j + 1][((s << 1) & ss) | 1] = (dp[i][j + 1][((s << 1) & ss) | 1] + dp[i][j][s]) % mod;
                    // cout << i << " " << j + 1 << " " << ((s << 1) & ss | 1) << " " << dp[i][j + 1][(s << 1) & ss | 1] << "\n";
                    if(sm1 >= j - i) continue;
                    dp[i + 1][j][(s << 1) & ss] = (dp[i + 1][j][(s << 1) & ss] + dp[i][j][s]) % mod;
                    // cout << i + 1 << " " << j << " " << ((s << 1) & ss) << " " << dp[i + 1][j][(s << 1) & ss] << "\n";
                }
                else {
                    dp[i][j + 1][((s << 1) & ss) | 1] = (dp[i][j + 1][((s << 1) & ss) | 1] + dp[i][j][s]) % mod;
                    // cout << i + 1 << " " << j << " " << ((s << 1) & ss) << " " << dp[i + 1][j][(s << 1) & ss] << "\n";
                    dp[i + 1][j][(s << 1) & ss] = (dp[i + 1][j][(s << 1) & ss] + dp[i][j][s]) % mod;
                    // cout << i << " " << j + 1 << " " << ((s << 1) & ss | 1) << " " << dp[i][j + 1][(s << 1) & ss | 1] << "\n";
                }
            }
        }
    }
    int ans = 0;
    for(int i = 0; i < (1 << k); i ++) ans = (ans + dp[n][n][i]) % mod;
    cout << ans << endl;

}

//

C.#

考虑到不能连续走 a,b,c 就是相当于不能连续走 (a,b),(b,c) 两条相邻的边,于是可以考虑将边转点跑最短路。

但是有一个问题是如果把边看成点跑最短路,那么边到边之间的转移可能会有 O(nm) 种,只需要建菊花图就能卡满。

但是考虑到整张图是不带权的,只要 dis 被更新就是最短路,那么我们可以直接把已更新的 dis 快速删掉,这样由于每个点的最短路只会被更新一次,当枚举到这个点却不更新其最短路时,当且仅当它属于 q 条限制里,而每条限制只会被枚举一次,故总枚举量是 O(n+q) 的。

现在考虑如何删除 dis,可以使用 set,vector,链表,map,unordered_map,unordered_set 等各种数据结构

D.#

50pts#

发现在序列中比较好做, f(i) 表示凑齐前 i 个的方案数, f(ai)+=f(ai1) 即可。

考虑把它放树上,在 dfs 的过程中统计答案即可,从根开始,进入子树时统计贡献,出子树的时候把贡献撤销即可。

时间复杂度 O(nq)

作者:wyyqwq

出处:https://www.cnblogs.com/wyyqwq/p/18563018

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   你说得太对辣  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示