AtCoder Beginner Contest 260 D E F

D - Draw Your Cards

题意: 按给定顺序对一系列卡牌进行堆叠,设当前操作数为x,如果现有堆的最上面存在一个数比x大且最接近x,那么就将x叠上去,叠完判断这一堆的的卡牌数是否等于k,是的话则清空该堆。如果现有堆不存在这个数,那么就另起一堆。
思路: 用set模拟即可,每一堆中的卡牌都会有相同的一个值tot,我们用vis数组记录下来,然后下次进行堆叠的时候即可取出堆顶的tot复制给当前的这个数。
代码

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const int N=5e5+5;
const ll inf=0x3f3f3f3f;
ll n,m,x,y;
int a[N];
void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    set<int>s;
    map<int,int>vis;
    int tot=0;
    map<int,int>cnt;
    map<int,int>ans;
    for(int i=1;i<=n;i++){
        auto it=s.lower_bound(a[i]);
        if(it==s.end()){
            s.insert(a[i]);
            vis[a[i]]=++tot;
            cnt[tot]++;
            if(cnt[tot]==m){
                s.erase(a[i]);
                ans[tot]=i;
            }
            // cout<<i<<"   insert"<<endl;
        }
        else {
            s.insert(a[i]);
            int tag=vis[*it];
            s.erase(it);
            vis[a[i]]=tag;
            cnt[tag]++;
            if(cnt[tag]==m){
                s.erase(a[i]);
                ans[tag]=i;

            }
        }
    }
    for(int i=1;i<=n;i++){
        if(ans[vis[i]])cout<<ans[vis[i]]<<endl;
        else cout<<-1<<endl;
    }
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T=1;
    // cin>>T;
    while(T--){solve();}
}

E - At Least One

题意: 给出n对数\(a_ib_i\),问1到m中有多少个好子串
好子串的定义是,对于每一对\(a_ib_i\),至少要有一个出现的串中。
思路: 类似于滑动窗口,利用双指针处理出适配左右端点l,r
可以算出当前区间对答案的贡献(左端点不动,右端点向右移动仍然是合法串,所以就有一个最短的串和最长的串的长度),利用差分对区间进行修改。
代码

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const int N=5e5+5;
const ll inf=0x3f3f3f3f;
signed main(){
    int n,m;cin>>n>>m;
    vector<int>a(n),b(n);
    for(int i=0;i<n;i++){
        cin>>a[i]>>b[i];
    }
    vector<vector<int>>ind(m+1);
    for(int i=0;i<n;i++){
        ind[a[i]].push_back(i);
        ind[b[i]].push_back(i);
    }
    vector<int>cnt(n),ans(m+5);
    int num=n;
    for(int i=1,j=1;i<=m;){
        while(j<=m&&num!=0){
            for(auto x:ind[j]){
                if(cnt[x]==0)num--;
                cnt[x]++;
            }
            j++;
        }
        if(num!=0)break;
        ans[j-i]++;
        ans[(m+1-i)+1]--;
        for(auto x:ind[i]){
            cnt[x]--;
            if(cnt[x]==0)num++;
        }
        i++;
    } 
    for(int i=1;i<=m;i++){
        
        ans[i]+=ans[i-1];
        cout<<ans[i]<<" ";
        
    }
    cout<<'\n';
    
}

F - Find 4-cycle

题意: 给定两个集合S,T,有m条边相连,每一条边中的其中一个点属于S,另一个属于T。问是否存在一个环,长度为4,存在输出每个点,不存在则-1。
思路: 可以注意到集合T中的点只有3000个,那么我们可以去\(n^2\)的枚举任意两个点u,v,判断是否存在集合S中的两个点相连。
代码

#include <bits/stdc++.h>
#define endl '\n';
#define ll long long 
using namespace std;
const int N = 5e5 + 5;
int a[N],b[N],p[N];
int dp[3005][3005];
vector<int>G[N];
void solve() {
    memset(dp,-1,sizeof(dp));
    int s, t, m;
    cin >> s >> t >> m;
    
    for(int i = 0; i < m; i ++) {
        int u, v;
        cin >> u >> v;
        G[u].push_back(v-s);
    }
    for(int i =1; i <= s; i ++) {
        for(auto u : G[i]){
            for(auto v : G[i]){
                if(u == v)continue;
                if(dp[u][v] != -1){
                    cout << i << " " << dp[u][v] << " ";
                    cout<< u + s << " " << v + s << '\n';
                    return ;
                }
                dp[u][v] = i;
            }
        }
    }
    cout << -1 << endl;
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) { solve(); }
}
posted @ 2022-07-18 10:04  LiAnG24  阅读(89)  评论(0)    收藏  举报