Codeforces Round #837 (Div. 2) A~F

A. Hossam and Combinatorics

统计一下最小和最大值的个数分别是多少,则 a n s = 2 ∗ c n t m i n ∗ c n t m a x ans=2*cnt_{min}*cnt_{max} ans=2cntmincntmax,如果最大值等于最小值, a n s = 2 ∗ n ∗ ( n − 1 ) ans=2*n*(n-1) ans=2n(n1)

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;
cc_hash_table<int,int>mp;

int read() {
    
    
    int x=1,res=0;
    char c=getchar();
    while(c<'0'||c>'9') {
    
    
        if(c=='-') x=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
    
    
        res=res*10+(c-'0');
        c=getchar();
    }
    return res*x;
}

void solve() {
    
    
    int n=read(),ma=0,mi=1e9,cnt1=0,cnt2=0;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++) {
    
    
        a[i]=read();
        ma=max(ma,a[i]);
        mi=min(mi,a[i]);
    }
    for(int i=1;i<=n;i++) {
    
    
        if(a[i]==ma) cnt1++;
        if(a[i]==mi) cnt2++;
    }
    if(ma==mi) cout<<n*(n-1)<<'\n';
    else cout<<cnt1*cnt2*2<<'\n';
}

signed main()
{
    
    
    int t=read();
    while(t--) solve();
    return 0;
}

B. Hossam and Friends

对每一个左端点,维护他最远能到的右端点即可。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;
cc_hash_table<int,int>mp;

int read() {
    
    
    int x=1,res=0;
    char c=getchar();
    while(c<'0'||c>'9') {
    
    
        if(c=='-') x=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
    
    
        res=res*10+(c-'0');
        c=getchar();
    }
    return res*x;
}

struct node
{
    
    
    int l,r;
}g[maxn];


void solve() {
    
    
    int n=read(),m=read();
    vector<int>l(n+1),r(n+1);
    for(int i=1;i<=m;i++) {
    
    
        g[i].l=read();g[i].r=read();
        if(g[i].l>g[i].r) swap(g[i].l,g[i].r);
    }
    sort(g+1,g+1+m,[&](node a,node b){
    
    return a.l<b.l;});
    int now=m,mi=n,ans=0;
    for(int i=n;i>=1;i--) {
    
    
        while(now>=1&&g[now].l>=i) {
    
    
            mi=min(mi,g[now].r-1);
            now--;
        }
        ans+=(mi-i+1);
    }
    cout<<ans<<'\n';
}

signed main()
{
    
    
    int t=read();
    while(t--) solve();
    return 0;
}

C. Hossam and Trainees

分解质因数,然后把所有分解出的质因子放到一个map里面判重即可。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;


int read() {
    
    
    int x=1,res=0;
    char c=getchar();
    while(c<'0'||c>'9') {
    
    
        if(c=='-') x=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
    
    
        res=res*10+(c-'0');
        c=getchar();
    }
    return res*x;
}

struct node
{
    
    
    int l,r;
}g[maxn];
int p[maxn],cnt;

void solve() {
    
    
    int n=read(),pd=0;
    cc_hash_table<int,int>mp;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++) {
    
    
        a[i]=read();
        for(int j=1;j<=4e3;j++) {
    
    
            if(p[j]*p[j]>a[i]) break;
            if(a[i]%p[j]==0) {
    
    
                while(a[i]%p[j]==0) a[i]=a[i]/p[j];
                if(mp[p[j]]!=0) pd=1;
                mp[p[j]]=1;
            }
        }
        if(a[i]==1) continue;
        if(mp[a[i]]!=0) pd=1;
        mp[a[i]]=1;
    }
    if(pd==1) puts("YES");
    else puts("NO");
}
int vis[maxn];
signed main()
{
    
    
    for(int i=2;i<=1e5;i++) {
    
    
        if(!vis[i]) p[++cnt]=i;
        for(int j=i*i;j<=1e5;j+=i) {
    
    
            vis[j]=1;
        }
    }
    int t=read();
    while(t--) solve();
    return 0;
}

D. Hossam and (sub-)palindromic tree

先考虑区间版本的最长回文子序列求法,设 f i , j f_{i,j} fi,j表示区间 [ i , j ] [i,j] [i,j]的最长回文子序列的长度,则 f i , j = m a x { f i + 1 , j − 1 ,           a i ≠ a j f i + 1 , j − 1 + 2 ,    a i = a j f i + 1 , j                             f i , j − 1                             f_{i,j}=max \left\{\begin{matrix} f_{i+1,j-1},~~~~~~~~~a_i\neq a_j \\ f_{i+1,j-1}+2,~~a_i=a_j \\ f_{i+1,j}~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\ f_{i,j-1}~~~~~~~~~~~~~~~~~~~~~~~~~~~ \end{matrix}\right. fi,j=maxfi+1,j1,         ai=ajfi+1,j1+2,  ai=ajfi+1,j                           fi,j1                           
然后我们可以把这个dp放在树上进行,我们只需要把树上 n 2 n^2 n2条链按照序列的方法进行 d p dp dp即可,这样我们抽出树上的一条链的时候,只需要记录前驱和后继结点即可,另外用记忆化搜索可以很方便的的实现。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 3005
#define int long long
using namespace std;
using namespace __gnu_pbds;


int read() {
    
    
    int x=1,res=0;
    char c=getchar();
    while(c<'0'||c>'9') {
    
    
        if(c=='-') x=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
    
    
        res=res*10+(c-'0');
        c=getchar();
    }
    return res*x;
}
char a[maxn];
int nt[maxn],lt[maxn],f[maxn][maxn];

int cal(int l,int r) {
    
    
    if(f[l][r]) return f[l][r];
    if(nt[l]==r&&a[l]==a[r]) {
    
    return f[l][r]=2;}
    if(nt[l]==r&&a[l]!=a[r]) {
    
    return f[l][r]=1;}
    if(l==r) {
    
    return f[l][r]=1;}
    if(a[l]==a[r]) f[l][r]=max(f[l][r],cal(nt[l],lt[r])+2);
    f[l][r]=max(f[l][r] , cal(nt[l],r));
    f[l][r]=max(f[l][r] , cal(l,lt[r]));
    return f[l][r];
}

void solve() {
    
    
    int n=read(),ans=1;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=0;
    cin>>a+1;
    vector<int>de(n+1);
    vector<vector<int>>g(n+1);
    function<void(int,int,int)>dfs=[&](int x,int fa,int root) {
    
    
        if(de[x]==1) {
    
    ans=max(ans,cal(root,x));}
        for(int i:g[x]) {
    
    
            if(i!=fa) {
    
    
                nt[x]=i;lt[i]=x;
                dfs(i,x,root);
            }
        }
    };
    for(int i=1;i<n;i++) {
    
    
        int aa=read(),bb=read();
        g[aa].push_back(bb);
        g[bb].push_back(aa);
        de[aa]++;de[bb]++;
    }
    
    for(int i=1;i<=n;i++) {
    
    
        if(de[i]!=1) continue;
        dfs(i,0,i);
    }
    cout<<ans<<'\n';
}

signed main()
{
    
    
    int t=read();
    while(t--) solve();
    return 0;
}

E. Hossam and a Letter

题目大意:计算含有最多一个medium点并且不含任何bad点的H形状的连通块最多含有多少方格。
我们可以枚举两条竖线出现的位置,然后考虑两条竖线中出现m或者不出现m的两种情况。
对于两条竖线中出现一次m的情况,我们可以枚举m出现的位置然后上下扩展,得到每个m所属的区间后,再遍历这个区间判断中间的横是否全都是好点。
对于两条竖线中不出现m的情况,我们可以直接通过双指针的方法得到区间,再判断中间的横线是否出现m的次数小于等于1次。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;
cc_hash_table<int,int>mp;

int read() {
    
    
    int x=1,res=0;
    char c=getchar();
    while(c<'0'||c>'9') {
    
    
        if(c=='-') x=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
    
    
        res=res*10+(c-'0');
        c=getchar();
    }
    return res*x;
}

signed main()
{
    
    
    int n=read(),m=read(),ans=0;
    vector a(n+1,vector<int>(m+1));
    vector sum(n+1,vector<int>(m+1));
    for(int i=1;i<=n;i++) {
    
    
        for(int j=1;j<=m;j++) {
    
    
            char x;cin>>x;
            if(x=='.') a[i][j]=0;
            if(x=='m') a[i][j]=1;
            if(x=='#') a[i][j]=2;
            sum[i][j]=sum[i][j-1]+a[i][j];
        }
    }
    // cout<<"ok"<<endl;
    for(int i=1;i<=m;i++) {
    
    
        for(int j=i+2;j<=m;j++) {
    
    
            for(int l=1;l<=n;l++) {
    
    
                if(a[l][i]==0&&a[l][j]==0) {
    
    
                    int r=l;
                    while(r+1<=n&&a[r+1][i]==0&&a[r+1][j]==0) r++;
                    if(r-l<2) continue;
                    for(int s=l+1;s<r;s++) {
    
    
                        if(sum[s][j-1]-sum[s][i]<=1)ans=max(ans,j-i-1+2*(r-l+1));
                    //  ans+=(s-l)*(r-s);
                    }
                    l=r+1;
                }
            }
            for(int x=1;x<=n;x++) {
    
    
                if(a[x][i]+a[x][j]!=1) continue;
                int l=x,r=x;
                while(l-1>=1&&a[l-1][i]==0&&a[l-1][j]==0) l--;
                while(r+1<=n&&a[r+1][i]==0&&a[r+1][j]==0) r++;
                if(r-l<2) continue;
                for(int s=l+1;s<r;s++) {
    
    
                    if(sum[s][j-1]-sum[s][i]==0) 
                    ans=max(ans,j-i-1+2*(r-l+1));
                        // if(s<=x) ans+=(s-l)*(r-x);
                        // else ans+=(x-l)*(r-s);
                }
            }
        }
    }
    // cout<<"ok";
    cout<<ans<<"\n";
    return 0;
}

F. Hossam and Range Minimum Query

出现奇数次可以用异或和不等于零代替,然后我们对于每一个数随机一个对应的值,这样只需要用主席树就能求得最小的出现次数为奇数的数字。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#define time chrono::system_clock::now().time_since_epoch().count()
#include<ext/pb_ds/tree_policy.hpp>
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 400005
// #define int long long
using namespace std;
using namespace __gnu_pbds;
mt19937_64 rnd(time);
cc_hash_table<int,int>mp;

int read() {
    
    
    int x=1,res=0;
    char c=getchar();
    while(c<'0'||c>'9') {
    
    
        if(c=='-') x=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
    
    
        res=res*10+(c-'0');
        c=getchar();
    }
    return res*x;
}

struct tr {
    
    
    int l,r;
    unsigned long long val;
}t[maxn*20];
int root[maxn],cnt;

void build(int &k,int l,int r) {
    
    
    if(!k) k=++cnt;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(t[k].l,l,mid);
    build(t[k].r,mid+1,r);
}

void modify(int &k,int l,int r,int x,int val,int lt) {
    
    
    if(!k) k=++cnt;
    if(l==r) {
    
    t[k].val=(val^t[lt].val);return;}
    int mid=(l+r)>>1;
    if(x<=mid) {
    
    
        t[k].r=t[lt].r;
        modify(t[k].l,l,mid,x,val,t[lt].l);
    }
    else {
    
    
        t[k].l=t[lt].l;
        modify(t[k].r,mid+1,r,x,val,t[lt].r);
    }
    t[k].val=t[t[k].l].val^t[t[k].r].val;
}

int query(int k,int l,int r,int lt) {
    
    
    if(l==r) {
    
    
        return l;
    }
    int mid=(l+r)>>1;
    if(t[t[k].l].val!=t[t[lt].l].val) return query(t[k].l,l,mid,t[lt].l);
    else return query(t[k].r,mid+1,r,t[lt].r);
}

signed main()
{
    
    
    int n=read();
    vector<int>a(n+1),b(n+1);
    vector<unsigned long long>v(n+1);
    for(int i=1;i<=n;i++) {
    
    
        b[i]=a[i]=read();
    }
    sort(b.begin()+1,b.end());
    int m=unique(b.begin()+1,b.end())-b.begin()-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(b.begin()+1,b.begin()+1+m,a[i])-b.begin();
    for(int i=1;i<=m;i++) v[i]=rnd();
    build(root[0],1,m);
    // cout<<cnt<<endl;
    for(int i=1;i<=n;i++) {
    
    
        modify(root[i],1,m,a[i],v[a[i]],root[i-1]);
    }
    int q=read(),ans=0;
    while(q--) {
    
    
        int l=read(),r=read();
        l^=ans;r^=ans;
        // cout<<l<<" "<<r<<endl;
        if(t[root[r]].val==t[root[l-1]].val) ans=0;
        else ans=b[query(root[r],1,m,root[l-1])];
        cout<<ans<<'\n';
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NEUQ_snowy/article/details/128324221