1. [编程题] 回文序列
思路:本题采用双端队列来模拟题中的操作,并记录移动的次数。
源码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
deque<int> dq;
int n,tmp,ans=0;
cin>>n;
while(n--)
{
cin>>tmp;
dq.push_back(tmp);
}
while(dq.size()>1)
{
int f1 = dq.front();
dq.pop_front();
int b1 = dq.back();
dq.pop_back();
if(f1>b1)
{
int b2 = dq.back();
dq.pop_back();
dq.push_back(b1+b2);
dq.push_front(f1);
ans++;
}
if(b1>f1)
{
int f2 =dq.front();
dq.pop_front();
dq.push_front(f1+f2);
dq.push_back(b1);
ans++;
}
}
cout<<ans<<endl;
return 0;
}
2.[编程题] 优雅的点
思路:枚举第一区间的点,如果点在圆上,根据圆的关于原点的对称性,在第二、三、四象限也有相应的点。又因为给出的是半径的平方,那么在X轴和Y轴上也有4个点。加起来就可以得到点的数量
源码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int r,ans=0;
cin>>r;
for(int i=1;i<sqrt(r);i++)
{
double j;
j=sqrt(r-i*i);
if(int(j)==j)
ans++;
}
if(int(sqrt(r))==sqrt(r))
cout<<4*ans+4<<endl;
else
cout<<4*ans<<endl;
return 0;
}
3.[编程题] 跳石板
思路:本题使用动态规划,采取刷表法。因为每次跳的步数为K的约数,枚举约数时,采用一次判断出,两个约数,比如j为K的约数,那么K/j也为K的约数,这样枚举的范围就从2到sqrt(K)。之后,d[i]表示到达i时,需要的最小步数。刷新d[i+j]和d[i+i/j].在进行枚举约数的之前,一定要判断现在的状态是否可达,如果不可达,跳出循环。
源码:
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn = 100000+10;
int d[maxn],M,N;
int main()
{
memset(d,INF,sizeof(d));
cin>>M>>N;
d[M]=0;
for(int i=M;i<=N;i++)
{
if(d[i]==INF) continue;//关键剪枝
for (int j=2;j<=sqrt(i);j++)
{
if (i%j==0&&i+j<=N)//例如是2为i的约数.
d[i+j]=min(d[i]+1,d[i+j]);
if(i%j==0&&i+i/j<=N)//那么i/2也为i的约数
d[i+(i/j)]=min(d[i]+1,d[i+i/j]);
}
}
if(d[N]==INF)
cout<<-1;
else
{
cout<<d[N]<<endl;
}
return 0;
}
4.[编程题]暗黑字符串
思路:本题思路,查看牛客网拖仔的解析。点击打开链接
源码:
#include<iostream>
using namespace std;
//主要是推导公式:
//例如:在字符串BAA的后面只能有两种添加字符的方法
//1.添加和末尾相同的字符变成BAAA,一定不是暗黑的字符串
//2.添加和末尾不同的字符串变成BAAB或BAAC,一定不是暗黑字符串
//用dp[0]和dp[1]分别表示上一次的添加方式对应的暗黑字符串的个数
//所以公式为:dp[0] = temp0 + temp1; dp[1] = 2*temp0 + temp1;
long long blackNum(int n){
if(n == 1)return 3;
if(n == 2)return 9;
long long dp[2];
dp[0] = 3;
dp[1] = 6;
for(int i = 2;i<n;i++){
long long temp0 = dp[0];
long long temp1 = dp[1];
dp[0] = temp0 + temp1;
dp[1] = 2*temp0 + temp1;
}
return dp[0]+dp[1];
}
int main(){
int n;
while(cin>>n){
cout<<blackNum(n)<<endl;
}
return 0;
}
5.[编程题] 数字翻转
思路:本题直接模拟操作进行,rev的操作适合在字符串的环境下,所以,我还写了string2int 和int2string函数,实际上C++自带的有int转换为string和string转int的函数。
源码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100 ;
string rev(string& s)
{
for(int i=0;i<s.length()/2;i++)
{
char c;
c=s[i];
s[i]=s[s.length()-1-i];
s[s.length()-1-i]=c;
}
return s;
}
string int2string(int a)//倒序输出
{
char s[maxn];
int i=0;
while(a)
{
s[i++]='0'+a%10;
a=a/10;
}
s[i]='\0';
return s;
}
int string2int(string s)
{
int a=0;
for(int i=0;i<s.length();i++)
{
a+=(s[s.length()-1-i]-'0')*pow(10,i);
}
return a;
}
int main()
{
string x,y;
cin>>x>>y;
cout<<string2int(int2string(string2int(rev(x))+string2int(rev(y))))<<endl;
return 0;
}
6.[编程题] 最大的奇约数
思路:本题采用常规方法都要超时,下面的代码思路为,因为求的结果是最大奇约数的和,那么只要是奇数,奇数*2为偶数,如果这个偶数在范围内,那么结果就加这个奇数。表示奇数*2的偶数的最大奇约数为这个奇数,遍历所有奇数,并根据以上规则将所有偶数的最大奇约相加,就可得。
注意:本代码有些轻微超时,在提交牛客网系统的时,可能出现只通过80%的情况,多提交几次就AC了。算一个投机的行为吧。
源码:
#include<stdio.h>
int main()
{
long long N;
long long sum=0;
scanf("%lld",&N);
for(long long i=1;i<=N;i+=2)
{
int j=i;
while(j<=N)
{
sum+=i;
j=j*2;
}
}
printf("%lld\n",sum);
return 0;
}
7.[编程题] 买苹果
思路:简单动态规划,记忆化搜索就好。
源码:
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int solve(int n)
{
if(n<=0) return inf;
if(n==6) return 1;
if(n==8) return 1;
else
{
return min(solve(n-6)+1,solve(n-8)+1);
}
}
int main()
{
int n;
cin>>n;
if(solve(n)>=inf)
cout<<-1;
else
cout<<solve(n)<<endl;
return 0;
}
8.[编程题] 计算糖果
思路:本题目已知,A B C 的取值范围为-30到30的整数,那么枚举A,通过A-B算出B,通过B-C算出C。如果计算的出的A B C 满足A+B和B+C,那么就输出A B C,如果在枚举完之后,没有符合条件的A B C,则输出No就可。
源码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int A,B,C;
int flag=0;
int c1,c2,c3,c4;
cin>>c1>>c2>>c3>>c4;
for(int A=-30;A<=30;A++)
{
B=A-c1;
C=B-c2;
if(A+B==c3&&B+C==c4)
{
cout<<A<<" "<<B<<" "<<C<<endl;
flag=1;
break;
}
}
if(!flag)
cout<<"No"<<endl;
return 0;
}