Codeforces Round #837 (Div. 2)补题

CF837A-D

A. Hossam and Combinatorics

题解:记录序列里面不同值出现的次数,如果序列里面只有一个值出现n次,则答案为n*(n-1),否则,答案为Count(max)*Count(min)*2,记得开long long

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6;
int n,a[N];
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    while(T--)
    {
        cin>>n;
        int maxx=0,minn=1e9;
        map<int,int>mp;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            maxx=max(a[i],maxx);
            minn=min(minn,a[i]);
            mp[a[i]]++;
        }
        if(maxx!=minn)
        cout<<mp[maxx]*mp[minn]*2<<"\n";
        else
            cout<<mp[maxx]*(mp[maxx]-1)<<"\n";
    }
    return 0;
}

B. Hossam and Friends

题解:预处理a[i]表示比i大的跟i不是朋友关系编号最小的人,单纯然后对每个i去求的话,可能会有不可增加的段数被增加了,例如若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>
using namespace std;
#define int long long
const int N=1e6;
int n,a[N],m;
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    while(T--)
    {
        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)
            {
                a[x]=min(a[x],y);
            }
            else
            {
                a[y]=min(a[y],x);
            }
        }
        int ans=0;
        for(int i=n-1;i>=1;i--)
            a[i]=min(a[i],a[i+1]);//这一步减少无效段数很重要
        for(int i=1;i<=n;i++)
            ans+=a[i]-i;
        cout<<ans<<"\n";
    }
    return 0;
}

C. Hossam and Trainees

题解:题意意思是,给你n个数,如果存在有两个数不互质,那么输出YES,否则输出NO,观察到这n个数最大为1e9,有一个数论小知识(已纠正):任何合数X的所有质因数都不会超过他的\sqrt{X}。那么我们可以预处理\sqrt{1e9}之内的所有质数,然后用一个map来储存当前拥有质数的个数。每次输进来一个数x,对他进行质因数分解,并且记录质数。当有记录的质数的个数等于两个时,则存在有两个数他们分解的质因数有相同的值,这时他们一定不互质,则输出YES。

#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e7;
int a[N],b[N],n,m,x,y,z,t,k,q;
int ans,res;
int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉
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] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    get_primes(int(sqrt(1e9)));//预处理出质数进行质因数分解
    cin>>T;
    while(T--)
    {
        map<int,int>mp;
        cin>>n;
        bool ok=true;
        for(int i=1; i<=n; i++)
        {
            cin>>x;
            if(ok)
            {
                //从0开始,到第cnt-1个结束,避免RE
                for (int j = 0; primes[j]*primes[j]<=x&&j<cnt; j ++ )
                {
                    int k=primes[j];
                    if (x % k == 0)
                    {
                        while (x % k == 0) x /= k;
                        mp[k]++;
                        if(mp[k]==2)
                        {
                            ok=false;
                            break;
                        }
                    }
                }
            }
            if(x>1)mp[x]++;
            if(mp[x]==2)ok=false;
        }
        if(ok)cout<<"NO"<<"\n";
        else cout<<"YES"<<"\n";
    }
    return 0;
}

D. Hossam and (sub-)palindromic tree

题解:

题意是给你一棵树,每个结点都有一个字符,任意两个结点之间的距离,距离经过的点和这两个点构成一个字符序列,求这个树里面,所有字符序列中回文序列个数最多的,求该最多个数数量。注意是字符序列,序列里面的回文序列,不是回文串,也就是说一段序列abxyab中,他是存在回文序列的,为abab,长度为4,先求所有序列中长度最长的。

记录一下做法,先n次dfs预处理出,以点i为根,所有节点的父亲节点为多少,即fa[i][j] :表示以j为根节点,i的父亲节点为fa[i][j]。然后为了求最长的回文串,对任意两对节点,都需要求一遍,他们路径上的最长回文串。

用递归的做法,再加上记忆化,详细见代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
int n;
string s;
vector<int>v[N];
int dp[2010][2010];
int fa[2010][2010];
void dfs(int x,int y,int z)
{
    fa[x][z]=y;
    for(auto w:v[x])
    {
        if(w==y)continue;
        dfs(w,x,z);
    }
}
int ddfs(int x,int y)//求x到y的路径上最长的回文序列
{
    if(x==y)//若x等于y,则只有一个字符,最长回文序列长度为1
        return 1;
    if(fa[x][y]==y)//若x的父亲就是y,直接判断即可
        return ((s[x]==s[y])? 2 : 1);
    if(dp[x][y]!=-1)//记忆化
        return dp[x][y];
    int anss=0;
    //x与y之间的路径,可以分为以x为树根或者以y为树根两种情况
    anss=max(ddfs(fa[x][y],y),ddfs(x,fa[y][x]));
    //若x和y的字符相同,则只需考虑彼此父亲的情况
    if(s[x]==s[y])
        anss=max(anss,ddfs(fa[x][y],fa[y][x])+2);
    return dp[x][y]=anss;//记忆化
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        cin>>s;
        for(int i=1;i<=n;i++)
        {
            v[i].clear();
            for(int j=1;j<=n;j++)
            {
                dp[i][j]=-1;
                fa[i][j]=0;
            }
        }
        s=" "+s;
        for(int i=1;i<=n-1;i++)
        {
            int x,y;
            cin>>x>>y;
            v[x].push_back(y);
            v[y].push_back(x);
        }
        int ans=1;
        for(int i=1;i<=n;i++)//预处理
            dfs(i,0,i);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                ans=max(ans,ddfs(i,j));
            }
        }
        cout<<ans<<"\n";
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值