链接:https://www.nowcoder.com/acm/contest/90#question
D | psd面试 |
解析:注意是最长的回文子序列不是最长回文子串,用字符串长度减去最长回文子序列长度就是答案。
代码:
#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 | 回旋星空 |
解析:枚举每个转折点来处理
代码:
#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 | 等式 |
解析:公式可以转化为(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;
}