D题 psd面试
题意:求最长回文子序列。
一定注意回文子序列和回文子串不是一回事,另外除了题目要求忽略字母大小写以外不要删除字符。
其他没什么了,直接用老办法dp干就可以了。还有dfs做的话会超时。
代码:
int DP_LPS(string str)
{
int n=str.size();
int tmp;
vector< vector<int> > dp(n,vector<int>(n,0));
for(int
tmp=dp[j+1][j+i-1] + 2;
}
elsei=0;i<n;i++)
{//(1)一个元素的最长子序列
dp[i][i]=1;
}
//(2)对于每一个[j,j+i]子序列的lps
for(int i=1;i<n;i++)
{
tmp=0;
for(int j=0;j+i<n;j++)
{
if(str[j] == str[j+i])
{//首尾相同
{//首尾不同
tmp=max(dp[j+1][j+i], dp[j][j+i-1]);
}
dp[j][j+i]=tmp;//得到[j,j+i]子序列的LPS
}
}
return dp[0][n-1];
}
int main()
{
string s,s2;
while(cin>>s)
{
int le=s.size();
s2="";//清空操作
for(int i=0;i<le;i++)
{
if(s[i]>='A'&&s[i]<='Z')s2+=(s[i]+32);
else s2+=s[i];
}
cout<<le-DP_LPS(s2)<<endl;
}
return 0;
}
E题:回旋星空
题意:计算回旋图标的个数,即选中三颗星星,分别作为回旋图标的起点,拐点和终点,假设现在有三个星星分别为i,j,k,如果d(a[i],a[j]) == d(a[j],a[k])则表示找到了一个回旋图标,其中d(x,y)表示这两个点的欧氏距离为了给它很大的希望(i,j,k)和(k,j,i)被认为是两个不同的回旋图标。
这道题目所给的数据量只允许n^2,所以其实就是一点点小技巧而已。
先用枚举所有点i,计算出该点i到其他所有点的距离存入一个map<double,int>,其中map是记录i点打其他所有点距离为double的点个数int。那么经过该点的成功组合数为C(int,2)*2。
代码:
const int maxn=1024;
struct node
{
int x,y;
}a[maxn];
double dis(node a,node b)
{
return sqrt(double((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}
map<double,int>q;
map<double,int>::iterator it;
int main()
{
int t;
scanf("%d",&t);
for(int m=0;m<t;m++)
{
int c=0;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
if(n<3) {cout<<"WA"<<endl;continue;}
q.clear();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
q[dis(a[i],a[j])]++;
}
for(it=q.begin();it!=q.end();it++)
{
int zz=it->second;
if(zz>=2) c=c+(zz-1)*zz/2;
}
q.clear();
}
if(c!=0)cout<<c*2<<endl;
else cout<<"WA"<<endl;
}
return 0;
}
F题:等式
题意:给定n,求1/x + 1/y = 1/n (x<=y)的解数。(x、y、n均为正整数)
这题就是推导一下,先通分,在移项,两边都加n^2,整合式子变成(x-n)(y-n)=n^2,问题自然转化成求n^2有多少个满足条件的因数,因为n=(p1^a1)...(pn^a1),所以n^2=(p1^(2a1))...(pn^(2an)),那么显然n^2有(2a1+1)...(2an+1)个因数,毕竟pi可以取0个,1个,,,ai个。最后得出因子数x在输出(x+1)/2就行了。。。这道题其实挺水的。
代码:
const int MAXN = 1000000;
bool flag[MAXN];
int primes[MAXN / 3], pi;
void prime()
{
int i, j;
pi = 0;
memset(flag, false, sizeof(flag));
for (i = 2; i < MAXN; i++)
{
if (!flag[i])
primes[pi++] = i;
for (j = 0; (j < pi) && (i * primes[j] < MAXN); j++)
{
flag[i * primes[j]] = true;
if (i % primes[j] == 0) //这句保证每个非素数只被筛去一次
break;
}
}
}
ll p[10005],cnt;
void solve(ll n)
{
cnt=0;
for(int i=0;i<pi&&primes[i]<=n;i++)
{
if(n%primes[i]==0)
{
ll k=0;
while(n%primes[i]==0)
{
n/=primes[i];
k++;
}
p[++cnt]=k;
}
}
if(n>1) p[++cnt]=1;
}
int main()
{
int T;
prime();
scanf("%d",&T);
while(T--)
{
ll n,ans=1;
scanf("%lld",&n);
solve(n);//分解一下因数,保存每个因子的次方数
for(int i=1;i<=cnt;i++)
{
ans=ans*(2*p[i]+1);
}
cout<<(ans+1)/2<<endl;
}
}
J题:强迫症序列
题意:他十分希望数组的每一个元素都一样大,每次操作只给这个数组的其中n-1个元素加1。
貌似这道题我们做出来的方法和题解不太一样。
就是给出一个序列一次操作给n-1个+1,相当于给其中一个-1,那么最小值和其他所有数的差加起来就是操作次数,然后最小值加操作次数就是最终状态。
代码:
using namespace std;
const int maxn=110000;
int dp[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
long long mi=11000;
for(int i=1;i<=n;i++)
{
scanf("%d",&dp[i]);
if(mi>dp[i])mi=dp[i];
}
long long sum=0;
for(int i=1;i<=n;i++)
{
sum+=dp[i]-mi;
}
printf("%lld %lld\n",sum,sum+mi);
}
return 0;
}
L题:用来作弊的药水
题意:给出a,x,b,y判断a^x是否等于b^y,这个提就是快速幂,取模只要大于1e9的一个素数就行
代码:
const ll mod=1e9+7;
long long pow_mod(long long a,long long b,long long m)
{
long long ans = 1;
while(b)
{
if(b&1)//判断此时b[i]的二进制位是否为1
{
ans = (ans*a)%m;//乘到结果上,这里a是a^(2^i)%m
b--;//把该为变0
}
b/=2;
a = a*a%m;
}
return ans;
}
int main()
{
ll x,y,a,b;
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld%lld",&x,&a,&y,&b);
ll ans1,ans2;
ans1=pow_mod(x,a,mod);
ans2=pow_mod(y,b,mod);
if(ans1==ans2) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
本文精选了几道算法竞赛题目并提供了详细的解决方案,包括最长回文子序列、计算回旋图标的个数、求等式的解数等问题,通过动态规划、数学推导等方法解决了这些问题。
题目整理)&spm=1001.2101.3001.5002&articleId=79691149&d=1&t=3&u=d6941ea4b21b40a3be77d03f9089bb03)
401

被折叠的 条评论
为什么被折叠?



