训练记录番外篇(1):2022-2023 ICPC Brazil Subregional Programming Contest

2022.10.15
这个系列记录各种单人vp/组队vp省赛or外国区域赛的内容。
也基本和之前一样只有简要解释和ac代码。
在这里插入图片描述

A. Finding Maximal Non-Trivial Monotones

求有多少个A边上有A,直接写就好了

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e5 + 10;
int a[N];
inline void solve(){
    int n = 0; cin >> n;
    string s; cin >> s, s = '@' + s;
    int cnt = 0, ans = 0;
    for(int i = 1; i <= n; i++){
        if(s[i] == 'a') cnt++;
        else{
            if(cnt >= 2) ans += cnt;
            cnt = 0;
        }
    }
    if(cnt >= 2) ans += cnt;
    cout << ans << endl;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

B. Fun with Stones

三堆石子的尼姆游戏,每堆石子一定是在某个范围中随机选择,求Alice胜利的概率。
首先容易转化为求 a ∈ [ l 1 , r 1 ] & & b ∈ [ l 2 , r 2 ] & & c ∈ [ l 3 , r 3 ] & & a ⊕ b ⊕ c = 0 a \in [l_1,r_1] \&\& b \in [l_2,r_2] \&\& c \in [l_3,r_3] \&\& a \oplus b \oplus c =0 a[l1,r1]&&b[l2,r2]&&c[l3,r3]&&abc=0。然后发现对于三个都处于该区间的条件是可以通过容斥出来的。
考虑做8次数位dp,每次都是满足 a ≤ x & & b ≤ y & & c ≤ z a \leq x\&\& b \leq y \&\& c \leq z ax&&by&&cz 的三个数异或为0的方案数直接做数位dp即可。
一个简单的数位dp方式是,从低位到高位考虑,按照三个数的后缀小于等于限制或大于可以分成八种情况。在考虑每一位的方案时发现只有四种情况,考虑四种情况和限制对大小的影响即可。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;
int l1,r1,l2,r2,l3,r3;
int dp[40][10];
int way[]={0,3,5,6};
int qpow(int x,int y,int res=1){
    for(;y;y>>=1,(x*=x)%=mod) if(y&1) (res*=x)%=mod;
    return res;
}
int ck(int x,int y,int z){
    int res=0;
    for(int i=0;i<3;i++){
        int fg1=((x>>i)&1),fg2=((y>>i)&1),fg3=((z>>i)&1);
        if(fg1!=fg2){
            res+=(fg1<<i);
        }
        else{
            res+=(fg3<<i);
        }
    }
    return res;
}
int dfs(int x,int y,int z){
    memset(dp,0,sizeof dp);
    dp[0][0]=1;
    for(int i=0;i<32;i++){
        int fg1=((x>>i)&1),fg2=((y>>i)&1),fg3=((z>>i)&1);
        int now=fg1*4+fg2*2+fg3;
        for(auto t:way){
            for(int j=0;j<8;j++){
                (dp[i+1][ck(t,now,j)]+=dp[i][j])%=mod;
            }
        }
    }
    return dp[32][0];
}
inline void solve(){
    cin>>l1>>r1>>l2>>r2>>l3>>r3;
    int ans1=dfs(r1,r2,r3),
        ans2=dfs(r1,r2,l3-1),
        ans3=dfs(r1,l2-1,r3),
        ans4=dfs(r1,l2-1,l3-1),
        ans5=dfs(l1-1,r2,r3),
        ans6=dfs(l1-1,r2,l3-1),
        ans7=dfs(l1-1,l2-1,r3),
        ans8=dfs(l1-1,l2-1,l3-1);
    int fenzi=((ans1-ans2-ans3+ans4-ans5+ans6+ans7-ans8)%mod+mod)%mod;
    int fenmu=(r1-l1+1)*(r2-l2+1)%mod*(r3-l3+1)%mod;
    cout<<(mod+1-fenzi*qpow(fenmu,mod-2)%mod)%mod;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

C. Cutting with Lasers

队友单切,他说是模拟扫描线加一点讨论即可。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, MOD = 1e9 + 7;
struct point { int x, y; } p[N];
struct line { point st, ed; } l[N];
int col[1010][1010], row[1010][1010];
bool check (int x, int y){
	return (1 <= x) && (1000 >= x) && (1 <= y) && (1000 >= y);
}
bool vis[1010][1010];
int cal[N];
int getpos(int x, int y) { return x * 1001 + y; }
int find(int x, int y){
    if(vis[x][y]) return 0;
    vis[x][y] = 1, cal[1] = x * 1001 + y;;
    int cnt = 1;
    for(int st = 1, ed = 2; st < ed; st++){
        int nx = cal[st] / 1001, ny = cal[st] % 1001;
        if(check(nx, ny + 1) && !row[nx][ny] && !vis[nx][ny + 1]){
            vis[nx][ny + 1] = 1, cal[ed++] = getpos(nx, ny + 1), ++cnt;
        }
        if(check(nx, ny - 1) && !row[nx][ny - 1] && !vis[nx][ny - 1]){
            vis[nx][ny - 1] = 1, cal[ed++] = getpos(nx, ny - 1), ++cnt;
        }
        if(check(nx + 1, ny) && !col[nx][ny] && !vis[nx + 1][ny]){
            vis[nx + 1][ny] = 1, cal[ed++] = getpos(nx + 1, ny), ++cnt;
        }
        if(check(nx - 1, ny) && !col[nx - 1][ny] && !vis[nx - 1][ny]){
            vis[nx - 1][ny] = 1, cal[ed++] = getpos(nx - 1, ny), ++cnt;
        }
    }
    return cnt;
}
inline void solve(){
    int n = 0; cin >> n;
    for(int i = 1; i <= n + 1; i++) cin >> p[i].x >> p[i].y;
    int lastx = 0, lasty = 0;
    for(int i = 1; i <= n; i++){
        if(p[i].x == p[i + 1].x){
            int st = min(p[i].y, p[i + 1].y) + 1, ed = max(p[i].y, p[i + 1].y);
            for(int j = st; j <= ed; j++) col[p[i].x][j] = 1;
        } else {
            int st = min(p[i].x, p[i + 1].x) + 1, ed = max(p[i].x, p[i + 1].x);
            for(int j = st; j <= ed; j++) row[j][p[i].y] = 1;
        }
    }
    int ans = 0;
    find(1, 1);
    for(int i = 1; i <= 1000; i++){
        for(int j = 1; j <= 1000; j++) ans = max(ans, find(i, j));
    }
    cout << ans << endl;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

D. Displacing Particles

签到题,考虑检测过程就是对行列一起二分,考虑两个数输出被二分次数更多的次数即可。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
inline void solve(){
    int n,x,y;
    cin>>n>>x>>y;
    int cnt=0;
    for(;x%2==0&&y%2==0;cnt++,x/=2,y/=2);
    cout<<n-cnt-1;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

E. Eliminating Ballons

签到,贪心。
考虑一个高度为 h i h_i hi 的气球,如果前面有一个没被消耗掉的高度为 h i − 1 h_i -1 hi1的气球那就对答案次数没有影响。
注意数组大小。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, MOD = 1e9 + 7;
int a[N], b[N];
inline void solve(){
    int n = 0; cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++){
        if(b[a[i] + 1]) b[a[i] + 1] -= 1;
        b[a[i]] += 1;
    }
    int ans = 0;
    for(int i = 1; i <= 1e6; i++) ans += b[i];
    cout << ans << endl;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

F. Multidimensional Hangman

每个n个长度为c的匹配串,每个串中间有个通配符,求能匹配上最多匹配串的字典序最小字符串和其匹配数量。
每次把一个匹配串对应的所有可能字符串insert到map里,然后遍历map即可。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, MOD = 1e9 + 7;
map<string,int>mp;
inline void solve(){
    int n, c; cin >> n >> c;
    for(int i = 1; i <= n; i++){
        string s; cin >> s;
        int pos = 0;
        for(int j = 0; j < s.length(); j++) if(s[j] == '*') pos = j;
        for(int j = 0; j < 26; j++){
            s[pos] = (char)(j + 'a');
            mp[s]++;
        }
    }
    int ans=0;
    string anss="";
    for(auto [x,y]:mp){
        if(y>ans){
            anss=x;ans=y;
        }
    }
    cout<<anss<<" "<<ans;
}

signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

G. Geometry of Triangles

有若干个通过对称反转形成的三角形,要求保留部分三角形且轮廓不变,求最小面积。(保证三角形互不重叠)
容易发现将所有共边的三角形连边,形成的是一个树结构,考虑一个形如”没有上司的舞会“的树dp即可。
(vp后5min写出来sad喵)

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
#define double long double
using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;
int n,cnt;
struct point{
    int x,y;
    bool operator<(const point &t)const {
        return x<t.x||x==t.x&&y<t.y;
    }
    bool operator==(const point &t)const {
        return x==t.x&&y==t.y;
    }
};
struct node{
    point a,b;
    double dis(){ 
        return sqrtl(1.0 * (a.x - b.x) * (a.x - b.x) + 1.0 * (a.y - b.y) * (a.y - b.y)); 
    }
    bool operator<(const node &t)const {
        return a<t.a||a==t.a&&b<t.b;
    }
};
point minn(point x,point y){
    if(x.x<y.x||x.x==y.x&&x.y<y.y)return x;
    return y;
}
point maxx(point x,point y){
    if(x.x>y.x||x.x==y.x&&x.y>y.y)return x;
    return y;
}
map<node,int>mp;
vector<int>p[200005];
const double inf =1e18; 
double ww[N];
double dp[N][2];
void dfs(int u,int fa){
    for(auto v:p[u]){
        if(v==fa)continue;
        dfs(v,u);
    }
    dp[u][1]=ww[u];
    for(auto v:p[u]){
        if(v==fa)continue;
        dp[u][1]+=min(dp[v][0],dp[v][1]);
    }
    if(p[u].size()<=2){
        dp[u][0]=inf;
    }
    else{
        for(auto v:p[u]){
            if(v==fa)continue;
            dp[u][0]+=dp[v][1];
        }
    }
}
inline void solve(){
    cin>>n;
    for(int i=1;i<=n;i++){
        point q,w,e;
        cin>>q.x >> q.y >> w.x >> w.y >> e.x >> e.y;
        node edge1={minn(q, w), maxx(q, w)};
        node edge2={minn(e, w), maxx(e, w)};
        node edge3={minn(e, q), maxx(q, e)};
        if(mp.count(edge1)){
            p[mp[edge1]].emplace_back(i);
            p[i].emplace_back(mp[edge1]);
        }
        if(mp.count(edge2)){
            p[mp[edge2]].emplace_back(i);
            p[i].emplace_back(mp[edge2]);
        }
        if(mp.count(edge3)){
            p[mp[edge3]].emplace_back(i);
            p[i].emplace_back(mp[edge3]);
        }
        double d1=edge1.dis(),d2=edge2.dis(),d3=edge3.dis();
        double d4=(d1+d2+d3)/2;
        ww[i]=sqrtl(d4*(d4-d1)*(d4-d2)*(d4-d3));
        mp[edge1] = i;
        mp[edge2] = i;
        mp[edge3] = i;
    }
    dfs(1,0);
    cout<<min(dp[1][0],dp[1][1]);
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(1);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

H. Helping the Transit

强连通分量裸题。
缩完点输出没有出度和没有入度的点数量的max即可。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
int n, m;
int newid[N];
vector<int> p[N];
vector<vector<int>> scc;
int dfn[N], low[N], ins[N], idx, cnt;
vector<int> st, f;
void scc_tarjan(int u){
    low[u] = dfn[u] = ++idx;
    st.emplace_back(u);
    ins[u] = 1;
    for(auto v : p[u]){
        if(!dfn[v]) scc_tarjan(v);
        if(ins[v]) low[u] = min(low[u], low[v]);
    }
    if(low[u] == dfn[u]){
        ++cnt; 
        f.clear();
        while(1){
            int v = st.back(); st.pop_back();
            f.emplace_back(v);
            ins[v] = 0;
            newid[v] = cnt;
            if(u == v) break;
        }
        scc.emplace_back(f);
    }
}
vector<int>g[500005];
int ind[500005],outd[500005];
inline void solve(){
    cin >> n >> m;
    for(int i = 1; i <= m; i++){
        int u, v; cin >> u >> v;
        p[u].emplace_back(v);
    }
    for(int i = 1; i <= n; i++){
        if(dfn[i]) continue;
        scc_tarjan(i);
    }
    if(cnt==1){
        cout<<0<<endl;
        return;
    }
    for(int i=1;i<=n;i++){
        for(auto v:p[i]){
            if(newid[i]!=newid[v]){
                ind[newid[v]]++;
                outd[newid[i]]++;
            }
        }
    }
    int cnt1=0,cnt2=0;
    for(int i=1;i<=cnt;i++){
        if(ind[i]==0)cnt1++;
        if(outd[i]==0)cnt2++;
    }
    cout<<max(cnt1,cnt2);
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; //cin >> t;
    while(t--) solve();
    return 0;
}

I. Intercepting Information

签到 ,队友单切

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
inline void solve(){
    for(int i = 1; i <= 9; i++){
        int x; cin >> x;
        if(x == 9){ cout << 'F'; return; }
    }
    cout << 'S' << endl;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

J. Playing 23

队友写的,模拟一个23点的游戏,坑点有点多。
一个是输入的时候加分要和10取min
一个是每张牌至多四张。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, MOD = 1e9 + 7;
int a[N], b[N];
int mp[N];
inline void solve(){
    int n = 0; cin >> n;
    int cnt1 = 0, cnt2 = 0;
    int x;
    for(int i = 1; i <= 2; i++) cin >> x, mp[x]++, cnt1 += min(x,10ll);
    for(int i = 1; i <= 2; i++) cin >> x, mp[x]++, cnt2 += min(x,10ll);
    for(int i = 1; i <= n; i++){
        int x = 0; cin >> x, mp[x]++;
        cnt1 += min(x,10ll), cnt2 += min(x,10ll);
    }
    int r=23-cnt2, l=23-cnt1, ans=1e9;
    if(mp[r]<4) ans=r;
    if(l<r)
    {
        for(int i=l+1;i<=r;i++) 
        {
            if(mp[i]<4) ans=min(ans,i);
        }
    }
    if(ans<=10) 
    {
        cout<<ans<<"\n";
    }
    else cout<<"-1\n";
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

K. Kalel, the Jumping Frog

vp的时候想到了矩阵快速幂,没想到怎么压第三维。赛后问别人才知道,矩阵每点维护一个多项式即可。这题就是三个板子拼起来,裸的矩阵加速递推+矩阵快速幂+朴素多项式乘法。复杂度是 O ( d 3 k 2 l o g n ) O(d^3k^2logn) O(d3k2logn) 计算一下大约是1e9,但是开了15秒时间非常充裕。

#include <bits/stdc++.h>
#define int long long
//#define endl '\n'
#define lowbit(x) (x&(-x))
#define ull unsigned long long 
#define pii pair<int,int>
using namespace std;
const string yes="Yes\n",no="No\n";
const int N = 100005,inf = 1e18,mod=1000000007,M=1e9;
int qpow(int x,int y=mod-2,int mo=mod,int res=1){
    for(;y;(x*=x)%=mo,y>>=1)if(y&1)(res*=x)%=mo;
    return res;
}
struct poly{
    int a[401];
    void init(){memset(a,0,sizeof(a));}
    poly operator * (const poly &t) const{
        poly ans;ans.init();
        for(int i=0;i<=400;i++){
            for(int j=0;j<=i;j++){
                (ans.a[i]+=a[j]*t.a[i-j])%=M;
            }
        }
        return ans;
    }
    void operator += (const poly &t){
        for(int i=0;i<=400;i++){
            (a[i]+=t.a[i])%=M;
        }
    }
};
struct mat{
    poly a[10][10];
    void init(){memset(a,0,sizeof(a));}
    void init1(){
        memset(a,0,sizeof(a));
        for(int i=0;i<10;i++){
            a[i][i].a[0]=1;
        }
    }
    mat operator * (const mat &t)const{
        mat ans;ans.init();
        for(int i=0;i<10;i++){
            for(int j=0;j<10;j++){
                for(int k=0;k<10;k++){
                    ans.a[i][j]+=(a[i][k]*t.a[k][j]);
                }
            }
        }
        return ans;
    }
}ans,base;
mat qpow(mat x,int y){
    mat res;res.init1();
    for(;y;y>>=1,x=x*x)if(y&1)res=res*x;
    return res;
}
int n,m,k;
void solve(){
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        int d,p;cin>>d>>p;
        d--;base.a[0][d].a[p]++;
    }
    for(int i=1;i<10;i++){
        base.a[i][i-1].a[0]=1;
    }
    ans.a[0][0].a[0]=1;
    ans=qpow(base,n-1)*ans;
    int sum=0;
    for(int i=0;i<=k;i++){
        (sum+=ans.a[0][0].a[i])%=M;
    }
    cout<<sum;
}
signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cout<<fixed<<setprecision(12);
    int t=1;
    while (t--)
		solve();
}

L. Listing Tedious Paths

裸虚树dp 详细题解可以在知乎搜ygg。(还有树上启发式合并写法)

#include <bits/stdc++.h>
using namespace std;
vector<int>p[500005];
int dfn[500005],sz[500005],pr[500005],dep[500005],fa[500005];
int lst[500005];
int cnt,n;
void dfs1(int u){
    if(fa[u]!=0) p[u].erase(find(p[u].begin(),p[u].end(),fa[u]));
    sz[u]=1;
    for(auto v:p[u]){
        if(v==fa[u])continue;
        fa[v]=u;dep[v]=dep[u]+1;
        dfs1(v);
        sz[u]+=sz[v];
    }
    sort(p[u].begin(),p[u].end(),[](const int x,const int y){return sz[x]>sz[y];});
}
void dfs2(int u){
    dfn[u]=++cnt;
    for(auto v:p[u]){
        if(v==p[u][0]){pr[v]=pr[u];}
        else{pr[v]=v;}
        dfs2(v);
    }
    lst[u]=cnt;
}
int lca(int u,int v){
    while(pr[u]!=pr[v]){
        if(dep[pr[u]]>dep[pr[v]]){u=fa[pr[u]];}
        else{v=fa[pr[v]];}
    }
    return dep[u]<dep[v]?u:v;
}
vector<int>col[100005],now[100005],newtree[100005];
vector<int>st;
int c[100005],sum[100005],colcnt[100005],dpsz[100005];
int uu[100005],vv[100005];
void dfs3(int u){
    for(auto v:p[u]){
        dfs3(v);
        sum[u]+=sum[v];
    }
}
void dfs_dp(int u,int f,int color,int sumcol){
    if(c[u]==color)dpsz[u]=1;
    for(auto v:newtree[u]){
        dfs_dp(v,u,color,sumcol);
        dpsz[u]+=dpsz[v];
    }
    sum[u]+=dpsz[u]*(sumcol-dpsz[u]);
    sum[f]-=dpsz[u]*(sumcol-dpsz[u]);
}
void get(int color){
    sort(col[color].begin(),col[color].end(),[](const int x,const int y){return dfn[x]<dfn[y];});
    st.push_back(1);now[color].push_back(1);
    for(auto u:col[color]){//建立虚树
        if(u==1)continue;
        int LCA=lca(st.back(),u);
        while(st.size()>1&&dfn[st.back()]>dfn[LCA]){
            int v=st.back();st.pop_back();now[color].push_back(v);
            if(dfn[st.back()]>dfn[LCA]){
                newtree[st.back()].push_back(v);
            }
            else{
                newtree[LCA].push_back(v);
            }
        }
        if(LCA!=st.back())st.push_back(LCA);
        st.push_back(u);
    }
    while(st.size()>1){
        int u=st.back();st.pop_back();now[color].push_back(u);
        newtree[st.back()].push_back(u);
    }
    st.clear();
    //虚树上dp
    dfs_dp(1,0,color,col[color].size());
    for(auto x:now[color]){//清空
        dpsz[x]=0;
        newtree[x].clear();
    }
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i];
        colcnt[c[i]]++;
        col[c[i]].push_back(i);
    }
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        p[u].push_back(v);
        p[v].push_back(u);
        uu[i]=u;vv[i]=v;
    }
    dfs1(1);
    dfs2(1);
    for(int i=1;i<=n;i++){
        if(col[i].size())get(i);
    }
    dfs3(1);
    for(int i=1;i<n;i++){
        if(fa[uu[i]]==vv[i]){
            cout<<sum[uu[i]]<<" ";
        }
        else{
            cout<<sum[vv[i]]<<" ";
        }
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
}

N. Numbers on both Sides

两倍长,区间前k大和,主席树板子。

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;

const int N = 2e5 + 10, MOD = 1e9 + 7;

int a[N],b[N];

namespace PDT{
    #define ls lc[rt]
    #define rs rc[rt]
    int tree[N << 5], lc[N << 5], rc[N << 5], root[N], tot, sum[N<<5];
    void update(int &rt, int pre, int l, int r, int pos){
        rt = ++tot, lc[rt] = lc[pre], rc[rt] = rc[pre], tree[rt] = tree[pre] + 1, sum[rt] = sum[pre] + pos;
        if(l == r) return;
        int mid = l + r >> 1;
        if(mid >= pos) update(lc[rt], lc[pre], l, mid, pos);
        else update(rc[rt], rc[pre], mid + 1, r, pos);
    }
    int query(int l, int r, int L, int R, int k){
        if(l == r) return l * k;
        int mid = l + r >> 1, res = tree[rc[R]] - tree[rc[L]];
        if(res >= k) return query(mid+1, r, rc[L], rc[R], k);
        else return sum[rc[R]]-sum[rc[L]]+query(l, mid, lc[L], lc[R], k - res);
    }
}
using PDT::update;
using PDT::query;
using PDT::root;
int pre[N],ans,k,l;
inline void solve(){
    int n = 0; cin >> n;
    for(int i = 1; i <= n; i++) {cin >> a[i];a[i+n]=a[i];}
    for(int i = 1; i <= n; i++) {cin >> b[i];b[i+n]=b[i];}
    for(int i = 1; i <= 2*n; i++) update(root[i], root[i - 1], 1, 1e9, b[i]);
    for(int i=1;i<=2*n;i++){
        pre[i]=pre[i-1]+a[i];
    }
    cin>>k>>l;
    for(int i=n-k+1;i<=n+1;i++){
        ans=max(ans,pre[i+k-1]-pre[i-1]+query(1,1e9,root[i-1],root[i+k-1],l));
    }
    cout<<ans;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; //cin >> t;
    while(t--) solve();
    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值