第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛 - (D,E,F,J)

链接:https://www.nowcoder.com/acm/contest/90#question

Dpsd面试
题意:每组给出一个字符,问忽略字母大小写,这个字符串去掉 最长的回文子序列后还有多长?

解析:注意是最长的回文子序列不是最长回文子串,用字符串长度减去最长回文子序列长度就是答案。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define M 1300
char str[M];
int dp[M][M];

//动态规划求解最长回文子序列,时间复杂度为O(n^2)
int solve(int n)
{
    int tmp;
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;++i)
        dp[i][i]=1;

    for (int i=1;i<n;++i)
    {
        tmp=0;
        //考虑所有连续的长度为i+1的子串,str[j....j+i]
        for(int j=0;j+i<n;j++)
        {
            //如果首尾相同
            if (str[j]==str[j+i])
                tmp=dp[j+1][j+i-1]+2;
            //如果首尾不同
            else
                tmp=max(dp[j+1][j+i],dp[j][j+i-1]);
            dp[j][j+i]=tmp;
        }
    }
    return dp[0][n-1]; //返回字符串str[0...n-1]的最长回文子序列长度
}
int main()
{
    while(~scanf("%s",str))
    {
        int len=strlen(str);
        for(int i=0;i<len;i++)
        {
            if(str[i]>='A'&&str[i]<='Z')
                str[i]='a'+str[i]-'A';
        }
        printf("%d\n",len-solve(len));
    }
    return 0;
}

E回旋星空
题意:每组数据有一个n,表示有n个小星星,给出n个星星的坐标,计算回旋图标的个数,即选中三颗星星,分别作为回旋图标的起点,拐点和终点,假设现在有三个星星分别为i,j,k,如果distance(i,j) == distance(j,k)则表示找到了一个回旋图标,其中distance(x,y)表示这两个点之间的直线距离。这里(i,j,k)和(k,j,i)被认为是两个不同的回旋图标。

解析:枚举每个转折点来处理

代码:

#include <iostream>
#include <cstdio>
#include<algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
#define M 1005
#define exp 0.000001
int n,x[M],y[M];
double dis[M][M];
double p[M];
ll c[M];
void init() //计算组合数C(n,2)*2
{
    for(int i=2;i<50;i++)
    {
        ll temp=1;
        for(int j=i;j>=i-1;j--)
        {
            temp*=j;
        }
        c[i]=temp;
    }
}
inline double Distance(int i,int j)
{
    double x1,x2,y1,y2;
    x1=1.0*x[i]; x2=1.0*x[j];
    y1=1.0*y[i]; y2=1.0*y[j];
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
    init();
    int T,i,j,k;
    scanf("%d",&T);
    while(T--)
    {
        ll ans=0;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
        }
        for(i=1;i<=n;i++)  //i看做转折点
        {
            for(j=1;j<=n;j++)
                p[j]=Distance(i,j); //p数组就是其他所有点与转折点i的距离
            
            sort(p+1, p+1+n);
            int t=1;
            for(k=2; k<=n; k++)
            {
                if(p[k]-p[k-1]<exp)   //用t记录与i的距离相同的点的个数
                {
                    t++;
                }
                else
                {
                    if(t>=2)
                    {
                        ans+=c[t];
                    }
                    t=1;
                }
            }
            if(t>=2) //别忘了判断最后一个点
            {
                ans+=c[t];
            }
        }
        if(ans==0)
            printf("WA\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}
F等式
题意:给定n,求1/x + 1/y = 1/n (x<=y)的解的个数。(x、y、n均为正整数)

解析:公式可以转化为(x-n)*(y-n)=n*n,那么(x-n)和(y-n)都是n*n的因子,分析(x,y)的取值与分析(x-n,y-n)相同,我们可以直接求出n*n的因子的个数,方法是我们先对n*n分解质因数,n*n=p1^a1+p2^a2+..+pi^ai+...+pk^ak,那么我们用这些质因子组成因子时,pi可以取[0,ai]个共ai+1种取法,所以所有的因子个数就是(a1+1)*(a2+1)...*(an+1),(x-n,y-n)的方案数就是n*n的因子数,而由于x<=y,答案要除2.

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
ll x;
ll num;         //x*x的因子的个数
void init(ll n) //分解质因子
{
    for(int i=2;i*i<=n;i++)
    {
        ll res=0; //n包含因子i的个数
        if(n%i==0)
        {
            while(n%i==0)
            {
                n=n/i;
                res++;
            }
        }
        num=num*(res+1);
    }
    if(n>1)
        num=num*2;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld",&x);
        num=1;
        init(x*x);
        if(num%2)
            num=num/2+1;
        else
            num=num/2;
        printf("%lld\n",num);

    }
    return 0;
}
J强迫症的序列

题意:给出n的元素的a数组,对这个数组的操作有:每次对数组中的n-1个不同的数加1,问最少几次操作使得数组中的所有数一样大,输出这个值
解析:将n-1个数加1,相当于将所有数都加1,再将其中一个数减去1。将所有数都加1这个操作,其实不会改变任何数的 相对大小,也就是所有数两两之间的差都是不会变的,这对于要使所有元素均相等的目标来说没有影响,所以可以忽略这一部分。那么问题就变成每次选个数减1来达到目标的最小次数。要使次数最小,而且每次只能将元素减1,故应当把所有数减到与最小值相等。若n个元素为a0,a1,……,an-1,其中最小值为Min,则答案为(a0-Min)+(a1-Min)+……+(an-1-Min)。


代码:

#include <bits/stdc++.h>
#define M 100005
using namespace std;
int a[M];
int main()
{
    int n,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        
        sort(a,a+n);
        ll ans=0;
        for(int i=0;i<n;i++) 
            ans+=a[i]-a[0];
        ll s=a[0]+ans;
        cout<<ans<<" "<<s<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值