Codeforces Round #837 (Div. 2)

A

Hossam and Combinatorics

 题意:给定长度为n的数组,问有多少对(i,j)满足|a[i]-a[j]|=max|a[p]-q[q]|(1<=p,q<=n).

思路:求最大值的个数cnt1和最小值个数cnt2,注意当最大值等于最小值时,答案为n*(n-1);否则为2*cnt1*cnt2

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n;
int a[N];
void solve()
{
    int ma=-inf,mi=inf;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        ma=max(ma,a[i]);
        mi=min(mi,a[i]);
    }
    int cnt1=0,cnt2=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==ma) cnt1++;
        if(a[i]==mi) cnt2++;
    }
    if(cnt1==cnt2&&cnt1==n) cout<<(ll)n*(n-1)<<'\n';
    else cout<<(ll)2*cnt1*cnt2<<'\n';
}
int main()
{
    //ios;
    int _t=1;
    cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

B

 Hossam and Friends

题意:给定n和m,n个人编号1~n站成一排,m对关系,每队关系给定x和y,表示x号人和y号人不认识,问有多少个区间[l,r]满足区间内所有人都相互认识。

思路:处理每个人右边第一个不认识的人的位置。注意若a[i]=j,而在i和j之间可能还有x和y互相不是朋友(a[x]=y,且i<x<y<j),这样a[i]的贡献就不是j-i了,就应该是y-i,这样的话不妨让a[i]=y

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<long long,long long>
#define int long long
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n,m;
int a[N];
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) a[i]=n+1;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin>>x>>y;
        if(x>y) swap(x,y);
        a[x]=min(a[x],y);
    }
    for(int i=n-1;i>=1;i--)//减少无效段数
        a[i]=min(a[i],a[i+1]);
    
    ll ans=0;
    for(int i=1;i<=n;i++)
        ans+=a[i]-i;
    cout<<ans<<'\n';
}
signed main()
{
    //ios;
    int _t=1;
    cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

C

Hossam and Trainees

题意:给定长度为n的数组,问这些数中是否存在不互质的两个数,存在YES,不存在NO

思路:预处理1e5内的质数,map记录每个因子是否出现过。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<int,int>
#define int long long
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
bool st[N];
int primes[N],cnt;
void get_primes(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) primes[cnt++]=i;
        for(int j=0;primes[j]<=n/i;j++)
        {
            st[primes[j]*i]=1;
            if(i%primes[j]==0) break;
        }
    }
}
int n;
int a[N];
void solve()
{
    cin>>n;
    bool f=0;
    map<int,bool>mp;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(f) continue;

        for(int j=0;j<cnt&&primes[j]*primes[j]<=a[i];j++)
        {
            if(a[i]%primes[j]==0)
            {
                if(mp[primes[j]]) {f=1;break;}
                while(a[i]%primes[j]==0) a[i]/=primes[j];
                mp[primes[j]]=1;
            }
        }
        if(a[i]!=1)
        {
            if(mp[a[i]]) f=1;
            mp[a[i]]=1;
        }
    }
    if(f) puts("YES");
    else puts("NO");
}
signed main()
{
    //ios;
    get_primes(N);
    int _t=1;
    cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

D

Hossam and (sub-)palindromic tree

题意:给你n个点的树,树上节点是一个字符,问树上两点间简单路径形成的最长回文子序列的长度

思路:先考虑求一个字符串的最长回文子序列的长度,可以考虑动态规划,f[i][j]表示从第i个字符到第j个字符的最长回文子序列长度,那么,状态转移为:

若s[i]==s[j]:f[i][j]=2+f[i+1][j-1]

若s[i]!=s[j]:f[i][j]=max( f[i+1][j], f[i][j-1])

我们可以在O(n^2)的时间复杂度内解决

 

再来考虑如何在树上求,例如当我们求节点1到节点5的最长回文子序列时,先看节点1和节点5代表的字符是否相同,相同时,结果变成2+节点3到节点4之间的最长回文子序列;不同时,结果变成max(节点1到节点4,节点3到节点5),可以采用记忆化搜索,时间复杂度O(n^2).我们可以在dfs的过程中记录每个节点的父节点,用栈记录从根节点到该节点的路径。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<int,int>
typedef long long ll;
const int N=2e3+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n;
int h[N],e[2*N],ne[2*N],idx;
char s[N];
int fa[N];
int f[N][N];//从节点i到节点j的最长回文子序列长度
int st[N],tt;//栈记录从根节点到该节点的路径
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int ffa)
{
    fa[x]=ffa;
    f[x][x]=1;
    st[++tt]=x;
    for(int i=tt-2;i>=1;i--)
    {
        if(s[x]==s[st[i]]) f[x][st[i]]=f[st[i]][x]=2+f[fa[x]][st[i+1]];
        else f[x][st[i]]=f[st[i]][x]=max(f[x][st[i+1]],f[fa[x]][st[i]]);
    }
    for(int i=h[x];~i;i=ne[i])
    {
        int j=e[i];
        if(j==ffa) continue;
        if(s[j]==s[x]) f[x][j]=f[j][x]=2;
        else f[x][j]=f[j][x]=1;
        dfs(j,x);
    }
    --tt;
}
int fun(int x,int y)//求节点x与节点y之间的最长回文子序列长度
{
    if(f[x][y]!=-1) return f[x][y];
    else if(s[x]==s[y]) return f[x][y]=fun(fa[x],fa[y])+2;
    else return f[x][y]=max(fun(fa[x],y),fun(x,fa[y]));
}
void solve()
{
    cin>>n;
    for(int i=0;i<=n;i++) h[i]=-1,fa[i]=-1;
    idx=0;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            f[i][j]=-1;
    tt=0;

    scanf("%s",s+1);
    for(int i=1;i<=n-1;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);add(b,a);
    }
    
    dfs(1,-1);

    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            ans=max(ans,fun(i,j));
    
    cout<<ans<<'\n';
}
int main()
{
    //ios;
    int _t=1;
    cin>>_t;
    while(_t--) solve();
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_62615329/article/details/129189520