Codeforces Global Round 16

给定一棵树,可以合并花瓣,求最后叶节点个数
我们很多时候不是去模拟那个过程,而是找到等价的东西去维护去处理

#include<bits/stdc++.h>
using namespace std;
string a,b;
int n;
const int N = 4e5+10;
int h[N],ne[N],e[N],idx;
int ans;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void init(){
    memset(h, -1, sizeof h);
    idx=0;
    //memset(e,0,sizeof e);
    //memset(ne,0,sizeof ne);
    ans=1;
}
int dfs(int u,int fa){
    int cnt=0;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa)continue;
        cnt+=dfs(j,u);//cnt计算的是有多少个儿子
    }
    if(cnt>0){
        ans+=cnt-1;
        return 0;
        //这个儿子可以拆出来不用统计到父节点,而是统计到答案里去
    }
    return 1;//叶子节点返回一
}
void solve(){
    init();
    cin>>n;
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs(1,-1);
    cout<<ans<<endl;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--)solve();
}

有一个n行m列的表格

有n*m个人 每个人都有一个等级ai 题目中给出

对于任意两个人 i j 若ai>aj 则si>sj

其中si=第i个人坐的位置

假设坐(x,y) si= x*m+j

从1-n*m开始选座位 一个人进入每行时 他的不舒服程度 = 该行前面的的人数

问你最小不舒服程度

其实就是双关键字排序,值val就是第一关键字,按照
val升序排列,越小的排在越前面,如果val相等就按照下标升序排列
然后遍历每一行,进行cmp2排序
val相等的要降序排列
然后计算升序对数量
ans+=cal(i)
这里给出非离散化版本和离散化版本

#include<bits/stdc++.h>
using namespace std;
const int N = 301;
struct node{
    int val,index;
}a[N*N];
int n,m;
bool cmp1(node &x,node &y){
    if(x.val==y.val)return x.index<y.index;
    return x.val<y.val;
}
bool cmp2(node &x,node &y){
    if(x.val==y.val)return x.index>y.index;
    return x.val<y.val;
}
int cal(int i){
    int cnt=0;//确定升序对数量
    
    //确定每一行的左右端点
    int l=(i-1)*m+1;//左端点确定
    int r=i*m;//右端点确定
    sort(a+l,a+r+1,cmp2);
    // k  j这样的排列是否升序
    for(int j=r;j>l;j--){
        for(int k=j-1;k>=l;k--){
            if(a[k].index<a[j].index)cnt++;
        }
    }
    return cnt;
}
void solve(){
    int ans=0;
    cin>>n>>m;
    for(int i=1;i<=n*m;i++){
        int x;
        cin>>x;
        a[i]={x,i};
    }
    sort(a+1,a+n*m+1,cmp1);
    for(int i=1;i<=n;i++)ans+=cal(i);
    cout<<ans;
    cout<<'\n';
}
signed main(){
    int T;
    cin>>T;
    while(T--)solve();
}

#include<bits/stdc++.h>
using namespace std;
const int N = 301;
struct node{
    int val,index;
}a[N*N];
int n,m;
vector<int>b;
int find(int val){
    int l=0,r=b.size()-1;
    while(l<r){
        int mid=l+r>>1;
        if(b[mid]>=val)r=mid;
        else l=mid+1;
    }
    return r+1;
}
bool cmp1(node &x,node &y){
    if(x.val==y.val)return x.index<y.index;
    return x.val<y.val;
}
bool cmp2(node &x,node &y){
    if(x.val==y.val)return x.index>y.index;
    return x.val<y.val;
}
int cal(int i){
    int cnt=0;//确定升序对数量
    
    //确定每一行的左右端点
    int l=(i-1)*m+1;//左端点确定
    int r=i*m;//右端点确定
    sort(a+l,a+r+1,cmp2);
    // k  j这样的排列是否升序
    for(int j=r;j>l;j--){
        for(int k=j-1;k>=l;k--){
            if(a[k].index<a[j].index)cnt++;
        }
    }
    return cnt;
}
void solve(){
    b.clear();
    int ans=0;
    cin>>n>>m;
    for(int i=1;i<=n*m;i++){
        int x;
        cin>>x;
        a[i]={x,i};
        b.push_back(x);
    }
    sort(b.begin(),b.end());
    b.erase(unique(b.begin(),b.end()),b.end());
    
    for(int i=1;i<=n*m;i++)a[i].val=find(a[i].val);
    sort(a+1,a+n*m+1,cmp1);
    for(int i=1;i<=n;i++)ans+=cal(i);
    cout<<ans;
    cout<<'\n';
}
signed main(){
    int T;
    cin>>T;
    while(T--)solve();
}

在这里插入图片描述
补了6道题收获还是蛮大的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值