PTA上的题目,邀请码是72788f48072b80c5
7-1 n个数求和
题解
加减运算前、通分前注意约分,防止溢出
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
long long int gcd(long long int a,long long int b)
{
if(a<0)
a=-a;
return b==0?a:gcd(b,a%b);
}
int main()
{ int t;int i;
long long int sumx,sumy;
long long int l;
long long int a;
long long int x[105];long long int y[105];
while(scanf("%d",&t)!=EOF)
{
for(i=0;i<t;i++)
{
scanf("%lld/%lld",&x[i],&y[i]);
l=gcd(x[i],y[i]);
x[i]=x[i]/l;
y[i]=y[i]/l;
}
sumy=y[0]/gcd(y[0],y[1])*y[1];
sumx=x[0]*(y[1]/gcd(y[0],y[1]))+x[1]*(y[0]/gcd(y[0],y[1]));
l=gcd(sumx,sumy);
sumy/=l;
sumx/=l;
a=sumy;
for(i=2;i<t;i++)
{ sumy=sumy/gcd(sumy,y[i])*y[i];
sumx=sumx*(y[i]/gcd(a,y[i]))+x[i]*(a/gcd(a,y[i]));
l=gcd(sumx,sumy);
sumy/=l;
sumx/=l;
a=sumy;
}
l=sumx/sumy;
sumx=sumx-l*sumy;
if(l==0)
{
if(sumx!=0)
printf("%lld/%lld\n",sumx,sumy);
if(sumx==0)
printf("0\n");
}
if(l!=0)
{ if(sumx!=0)
printf("%lld %lld/%lld\n",l,sumx,sumy);
if(sumx==0)
printf("%lld\n",l);
}
for(i=0;i<105;i++)
{
x[i]=0;
y[i]=1;
}
}
}
7-2 比较大小
题解
直接读进数组sort就好,不过这是第一次用sort,所以多写了点方便观察sort的运行
#include<iostream>
#include <algorithm>
using namespace std;
int main()
{
int a,b,c;
cin>>a>>b>>c;
int arr[3];
arr[0]=a,arr[1]=b,arr[2]=c;
sort(arr,arr+3);
cout<<arr[0]<<"->"<<arr[1]<<"->"<<arr[2];
}
7-3 A-B
题解
做的时候直接O(nm)扫着删,边扫边删的话长度会动态更新,还有字符的位置也是,所以删除的时候要把索引退一位,不然会漏扫。
#include<iostream>
#include <algorithm>
#include<string>
using namespace std;
int main()
{
string a,b;
getline(cin,a);
getline(cin,b);
for(int i=0;i<b.length();++i)
{
for(int j=0;j<a.length();++j)
{
if(a[j]==b[i])
{
a.erase(j,1);
j--;
}
}
}
cout<<a;
}
7-4 计算指数
题解
我很抱歉下面出现了一些奇怪的斜体或者加粗,我在努力控制正确的格式。
如果把指数看成二进制,用分治的方法,可以把复杂度从O(n)降到O(logn).
用%可以拿到最低位的数,然后用/使指数右移一位,然后对x做一个平方。
比如2的7次方
7%2是1.y=x的1次方 7/2是3,然后对x=x*x
3%2是1,y等于x的(当前index%2)* y ,然后继续保持x=x*x;
把下面的a激活就可以算base的index次方,不过a和b都需要是正整数。
#include<iostream>
#include <algorithm>
#include<string>
using namespace std;
int _exp(int base,int index)
{
int r;
int x=base;
int y=1;
while(index!=0)
{
r=index%2;
index=index/2;
if(r==1)
{
y*=x;
}
x*=x;
}
return y;
}
int main()
{
int a,b;
cin>>b;
printf("2^%d = %d",b,_exp(2,b));
}
7-5 计算阶乘和
题解
没什么需要注意的……因为n最大是10
#include<iostream>
#include <algorithm>
#include<string>
using namespace std;
long long int jiecheng(int n)
{
long long int i,ans=1;
for(i=1;i<=n;++i)
{
ans*=i;
}
return ans;
}
int main()
{
int n;
cin>>n;
int i;
long long int ans=0;
for(i=1;i<=n;++i)
{
ans=ans+jiecheng(i);
}
cout<<ans;
}
7-6 简单题
#include<iostream>
#include <algorithm>
#include<string>
using namespace std;
int main()
{
cout<<"This is a simple problem.";
}
7-7 跟奥巴马一起画方块
题解
四舍五入可以使用int的对小数取整
#include<iostream>
#include <algorithm>
#include<string>
using namespace std;
int main()
{
int lie;
char c;
cin>>lie>>c;
int hang=(int)((lie*1.0)/2+0.5);
for(int i=0;i<hang;++i)
{
for(int j=0;j<lie;++j)
{
cout<<c;
}
cout<<endl;
}
}
7-8 查验身份证
题解
这题就申题看仔细就好了,先对前17按权重求和,接着%11后,去对应关系表里面找,也就是这个%11相当于一个索引。
#include<iostream>
#include <algorithm>
#include<string>
using namespace std;
int _right[17]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
char _find[11]={'1','0','X','9','8','7','6','5','4','3','2'};
bool legal(string a)
{
int ans=0;
bool flag=false;
for(int i=0;i<a.length()-1;++i)
{
ans+=((int)(a[i]-'0')*_right[i]);
}
// int asd=ans%11;
//cout<<a[17]<<endl;
// cout<<asd<<endl;
// cout<<_find[ans%11]<<endl;
if(_find[ans%11]==a[17])
{
// cout<<1<<endl;
flag=true;
}
return flag;
}
int main()
{
int n;
cin>>n;
string a;
int cnt=0;
while(n--)
{
bool flag;
cin>>a;
flag=legal(a);
if(flag==false)
{
cout<<a<<endl;
cnt++;
}
}
if(cnt==0)
{
cout<<"All passed";
}
}
7-9 集合相似度
题解
这题我用了stl的set,因为这样可以自带去重,而且元素有序,只需要做查找相同的元素个数和不相同的总数就好了,不过并不感觉这么写有简单。。
#include<iostream>
#include <algorithm>
#include<string>
#include<set>
using namespace std;
int main()
{
int n;
cin>>n;
int *num=new int[n];
set<int> *a=new set<int>[n];
for(int i=0;i<n;++i)
{
cin>>num[i];
int temp;
for(int j=0;j<num[i];++j)
{
cin>>temp;
a[i].insert(temp);
}
}
// for(int i=0;i<n;++i)
// {
// set<int>::iterator it;
// for(it=a[i].begin();it!=a[i].end();++it)
// {
// cout<<*it<<" ";
// }
// cout<<endl;
// }
cin>>n;
for(int i=0;i<n;++i)
{
int mo,mn;
int temp1,temp2;
int cnt=0;int _num=0;
cin>>mo>>mn;
temp1=mo-1;temp2=mn-1;
set<int>::iterator it1;
set<int>::iterator it2;
for(it1=a[temp1].begin(),it2=a[temp2].begin();it1!=a[temp1].end()&&it2!=a[temp2].end();)
{
if(*it1==*it2)
{
++it1;
++it2;
++cnt;
++_num;
}
else
{
if(*it1>*it2)
{
++it2;
++_num;
}
else
{
++it1;
++_num;
}
}
}
set<int>:: reverse_iterator _temp1=a[temp1].rbegin();
_temp1;
set<int>:: reverse_iterator _temp2=a[temp2].rbegin();
_temp2;
if(*_temp1!=*_temp2)
{
//cout<<*_temp1<<" "<<*_temp2<<endl;
++_num;
}
float ans=100.0*cnt/_num;
printf("%0.2f\%\n",ans);
}
}
7-10 中后序建树然后层次遍历
题解
这题建树的过程就是先从后序里找根,从中序里分左右子树,然后递归完成这个过程,接着用队列做一趟层次遍历。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
const int MAXN = 1e5;
int inOrder[MAXN], postOrder[MAXN];
struct binaryNode
{
int data;
binaryNode *left=NULL, *right=NULL;
};
binaryNode* BuildTree(int inB, int inE, int postB, int postE)
{
int i = 0;
binaryNode * root = new binaryNode;
root->data = postOrder[postE]; //后序遍历序列中获取根节点
while (inOrder[inB + i] != root->data) i++;//中序遍历序列中查找子树根节点位置
if (i > 0)//左子树存在
root->left = BuildTree(inB, inB + i - 1, postB, postB + i - 1);
if (inB + i < inE)//右子树存在
root->right = BuildTree(inB + i + 1, inE, postB + i, postE - 1);
return root;
}
void LevelTravel(binaryNode * root)
{
int cnt = 0;
queue<binaryNode *> s;
s.push(root);
binaryNode *temp;
while (!s.empty())
{
temp = s.front();
if (cnt == 0)
{
printf("%d", temp->data);
cnt = 1;
}
else
{
printf(" %d", temp->data);
}
if (temp->left)
s.push(temp->left);
if (temp->right)
s.push(temp->right);
s.pop();
}
}
int main()
{
int n;
cin >> n;
int i = 0;
while (cin >> postOrder[i++])
if (cin.get() != ' ') break;
i = 0;
while (cin >> inOrder[i++]) //get到每次读入一行的新方法
{
if (cin.get() != ' ')
{
break;
}
}
binaryNode * root = BuildTree(0, i - 1, 0, i - 1);
LevelTravel(root);
DeleteTree(root);
return 0;
}
7-11 家庭财产
题解
这题要整一个并查集,在我的另一个文章里有详解
7-12 最长对称子串
题解
这题有个诡异的地方就是a到底是对称还是不对称,如果不对称的话abc也是0,不然也是1,这是个坑。然后做的时候直接大致就是i往后走,j从0到i然后一直截取子串,判断是不是对称子串,这个好像叫马拉车算法。
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
bool isReverse(string s)
{
string t = s;
reverse(t.begin(), t.end());
if (s == t)
return true;
else
return false;
}
int main()
{
string s;//存放输入的串
string target;//用来存放截取出来的子串
int ans=1;//维护一个最大子串长度
getline(cin, s);//一行读入
for (unsigned i = 0; i < s.length(); i++)
{
for (int j = 0; j < i; j++)
{
target = s.substr(j, i+1);
if (isReverse(target) && target.length() > ans)
{
ans = target.length();
break;
}
}
}
cout << ans << endl;
return 0;
}