2024牛客多校第二场

B MST

类似根号分治的思路,点数少的跑Prim,点数大的跑Kruscal

有个坑点是分界点调100过不了,90能卡过去

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+5;
const ll inf = 1e16;
int n,m,Q;
struct ed{
    int u,v,w;
}edge[N<<1];
bool cmp(ed a,ed b){
    return a.w<b.w;
}


map<int,int>e[N];
struct S {
    int u;
    int d;
};
bool operator<(const S &x, const S &y) { return x.d > y.d; }
priority_queue<S> q;
int a[N];
bool vis[N];
void Prim(int n){
//    cout<<"Prim\n";
    for(int i=1;i<=n;i++) cin>>a[i],vis[a[i]]=0;
    
    q.push({a[1], 0});
    int cnt = 0;
    ll res=0;
    while (!q.empty() && cnt<=n ) {
        int u = q.top().u, d = q.top().d;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        ++cnt;
        res += d;
        //cout<<u<<" : "<<d<<"\n";
        for (int i = 1; i <= n ; i++ ) {
            int v = a[i];ll w = e[u][v];
            if (!vis[v] && w ) {
                q.push({v, w});
            }
        }
    }
    for(int i=1;i<=n;i++) vis[a[i]]=0;
    if(cnt>=n) cout<<res<<"\n";
    else cout<<-1<<"\n";
}

int pa[N];
int find(int x){
    if(pa[x]!=x) return pa[x]=find(pa[x]);
    return x;
}
void kruscal(int n){
//    cout<<"kruscal"<<"\n";
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) pa[a[i]]=a[i],vis[a[i]]=1;
    ll tot=0;
    int use=0;
    for(int i=1;i<=m;i++){
        if(!vis[edge[i].v] || !vis[edge[i].u] ) continue;
        int f1=find(edge[i].u),f2=find(edge[i].v);
        if(f1!=f2){
            tot+=edge[i].w;
            pa[f1]=f2;
            use++;
        }
    }
    if(use==n-1) cout<<tot<<"\n";
    else cout<<-1<<"\n";
    for(int i=1;i<=n;i++) pa[a[i]]=a[i],vis[a[i]]=0;
}

int main(){
//    freopen("3.in","r",stdin);
//    freopen("lys.out","w",stdout);
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m>>Q;
    int cnt=0;
    for(int i=1;i<=m;i++){
        int u,v,w;cin>>u>>v>>w;
        cnt++;
        edge[cnt]=(ed){u,v,w};
        e[u][v]=w;
        e[v][u]=w;
    }
    sort(edge+1,edge+1+m,cmp);
    int base=90;
    while(Q--){
        //TODO
        int k;cin>>k;
        if(k<=base){ // prim
            Prim(k);
        }
        else kruscal(k);
    }
}

 I

大概思路想的都差不多了,但是赛时在纠结如何计算" 区间剩下的数的个数 × 区间两端的值 "

"区间剩下的数的个数"不会处理,只想到加维度做成背包

但事实上完全可以在计算时直接算上贡献!如果该区间还包含更优的子区间,再用子区间的答案j进行更新就是了

这种类似先把贡献算好的思想之前遇到过。

赛时也没有设计好dp状态,如果能观察到其实是在n个区间内转移而非单纯的线性dp(这点真的很妙)

应该就能想到用g[i]表示当前在某个区间,枚举到当前区间第i个数的贡献

C

发现从左上角开始走是最优的,确定了起点就和普通递推没什么区别了

#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e6+505;
int n,res;
string c[2];
int f[N][2],s[N][2];
int main(){
    cin >> n;
    cin >> c[0] >> c[1];
    for (int i=1;i<=n;i++)
        for (int j=0;j<2;j++)
            if (c[j][i-1]=='R') s[i][j]=1;
    for (int i=1;i<=n;i++){
        for (int j=0;j<2;j++){
            if (s[i][j]){
                f[i][j]=f[i-1][j]+1;
                if (s[i][j^1])
                    f[i][j]=max(f[i][j],f[i-1][j^1]+2);
            }    
            res=max(res,f[i][j]);        
        }
    }
    
    if (res!=0) cout << res-1 << endl;
        else cout << 0 << endl;
    return 0;
}

E

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;
int T,x;
int lowbit(int x){
    return x&(-x);
}
void work(){
    cin >> x;
    int res=x-lowbit(x);
    if (res) cout << res << endl;
        else cout << -1 << endl;
}
signed main(){
    cin >> T;
    while(T--) work();
    return 0;
}

H

考虑拆成两维转化成前缀和,能经过点(x,y)首先要能走到(x,y)

对于固定的右端点r,相当于问有多少个点i满足

sumx[r]-sumx[i-1]=x

sumy[r]-sumy[i-1]=y

问题变成求这些点的后缀和,正着求不好求还可能算重,倒叙枚举i=n;i>=1;i--

对于当前枚举到的i,可能有很多的 j 比 i 大且都符合上面两个式子

只计算最小的那个 j ,显然只要加上这个 j 对应的后缀,所有的 j 都能不重不漏地考虑到

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5,dx[]={1,-1,0,0},dy[]={0,0,-1,1};
int n,x,y,ans=0;
char s[N+5];
map< pair<int,int>,int> sum;
int Mov(char ch)
{
    if(ch=='W') return 3;
    else if(ch=='S') return 2;
    else if(ch=='A') return 1;
    else return 0;
}
void Kafka()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>x>>y;
    cin>>s+1;
    if(x==0&&y==0)
    {
        cout<<n*(n+1)/2<<endl;
        return;
    }
    sum[make_pair(0,0)]=n;
    int Sx=0,Sy=0;
    for(int i=n;i;--i)
    {
        int now=Mov(s[i]);
        Sx+=dx[now],Sy+=dy[now];
//        printf("i=%d x=%d y=%d\n",i,Sx,Sy);
        int Nx=Sx-x,Ny=Sy-y;
        if(sum.find(make_pair(Nx,Ny))!=sum.end()) ans+=n-sum[make_pair(Nx,Ny)]+1;
        sum[make_pair(Sx,Sy)]=i-1;
//        printf("i=%d ans=%d\n",i,ans);
    }
    cout<<ans<<endl;    
}
signed main()
{
    Kafka();
    return 0;
}

 

posted @ 2024-07-22 11:13  liyishui  阅读(17)  评论(0编辑  收藏  举报