因为才知道2021年夏令营只能看本年的PAT成绩,所以冬季参加的就作废了。。
没办法只能参加这次的PAT。
这次的PAT是真的惊险,中间差点就以为自己无了,能告诉你我距离考试结束还有1:30的时候只有42分吗。。还好自己告诉自己别慌,也是因为最后一道题比较容易打把。
首先第一题:
第一题的意思是给你一个n,m,让你找到最后一项在m里面的n项等差数列,这道题思维难度比较低,因为等差数列只要确定了相邻的两项就可以确定一个等差数列了,所以只要先预处理m以内的质数然后O(n^2)的枚举最后一项和倒数第二项,就可以得出之前的项,然后一一看是不是质数就可以了。
然后你发现你TLE了。。
这个题还需要一些剪枝(大佬或常数小的人无视)
我的剪枝是如果这个数的第一项<2和如果nowdist<dist就不用看了,也就是v[j]-dis*(n-1)<1||nowdis<dist continue;
然后就过了.(很惊险的,一个点505ms…)
Code:
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
ll gcd(ll a, ll b){
if(a==0) return b;
else return gcd(b%a,a);
}
//tree<ll,null_type,less<ll>,rb_tree_tag,tree_node_statis_update> tr;
int isprime(int x){
if(x<2) return 0;
for(int i=2;i*i<=x;i++){
if(x%i==0) return 0;
}
return 1;
}
vector<int> v;
void prime(int n){
for(int i=2;i<=n;i++){
if(isprime(i)) v.push_back(i);
}
//sort(v.begin(),v.end());
}
vector<int> ans;
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
int n,m,dist=0,firnum=-1;
cin>>n>>m;
prime(m);//所有素数
int tag=0;
//for(int i=0;i<v.size();i++) cout<<v[i]<<' ';
ans.resize(n+7);
vector<int> v2;
for(int i=0;i<v.size();i++){
for(int j=i+1;j<v.size();j++){//一一枚举等差数列最后两项
int nowdis = v[j]-v[i];//当前的dis
if(nowdis<dist||v[j]-nowdis*(n-1)<2) continue;//剪枝
int len=n-2, now=v[i]-nowdis;
v2.clear();
v2.push_back(v[j]), v2.push_back(v[i]);
while(len>0){
if(isprime(now)){
v2.push_back(now), now-=nowdis, len--;//逐一向前
}
else break;
}
if(len==0&&(nowdis>dist||(nowdis==dist&&v2[v2.size()-1]>firnum))){//更新答案
for(int i=v2.size()-1;i>=0;i--){
ans[v2.size()-1-i]=v2[i];
}
firnum = ans[0], dist = nowdis;
tag=1;
}
}
}
if(!tag) cout<<v[v.size()-1];
else{
for(int i=0;i<n;i++){
cout<<ans[i];
if(i!=n-1) cout<<' ';
}
}
}
我能说第二题是我最后A的吗。。
我一直22分,然后发现自己时间求错了,substr使用算错了,就这都有22…
这道题是一个字符串模拟,加上基础的贪心就ok了
这道题就是给你N个区间,然后每个点只能有一段区间,问最多能放多少区间?
就是贪心选择结束时间最早的区间就行了,注意这里区间端点重叠也ok
#include<bits/stdc++.h>
using namespace std;
const int N = 2e3+7;
int toint(string s){
int x = 0;
for(int i=0;i<s.size();i++){
x = x*10+s[i]-'0';
}
return x;
}
int totime(string s){
string h=s.substr(0,2), m=s.substr(3,2), ss=s.substr(6,2);//(就是这里算成s.substr(5,2)了。。)
return toint(h)*3600+toint(m)*60+toint(ss);
}
struct line{
int from,to;
}g[N];
int cmp(line x,line y){
return x.to<y.to;
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
string s,s2;
for(int i=0;i<n;i++){
cin>>s>>s2;
g[i].from = totime(s), g[i].to = totime(s2);
if(g[i].from>=g[i].to) swap(g[i].from,g[i].to);
}
int ans = 0;
sort(g,g+n,cmp);
int last = -1;
for(int i=0;i<n;i++){
if(i==0||g[i].from>=last){
ans++;
last = g[i].to;
}
}
if(n==2000){//这个是开始想骗分。。。,后来发现是时间求错了
cout<<ans;
}
else cout<<ans;
}
第三题是让你模拟一个大顶堆(插入N个数字),然后有M个询问,问你这个询问对不对(都是什么x是不是y左儿子这样的)
这个题比较基础,但我一年没学基础数据结构,居然都把大顶堆忘记了,着急了5分钟,冷静的在纸面上写了写,就想起来了。。(花了我20分钟)
然后看了问题有点绝望(巨型的分类讨论+模拟啊),因为这个时候我离考试结束只有1:10了,只有42分。。。
但是也没有办法,喝了一大口水,然后开干,先用getline(cin,s),以空格为分界线,一点点扣字符串。
其实这道题难点主要是字符串模拟,大顶堆部分因为是一颗完全二叉树所以孩子就是x2+1和x2,父亲就是x/2,只要使用map模拟就行了,每次插入一点点向父亲更新就行,直到到根或者是满足大顶堆了。
复杂度O(n*lgn)(不过PAT一般不会TLE的)
然后两个map一个是key->val,一个是val->key
x,y兄弟->mp2[x]/2=mp2[y]/2
x根->mp[1]=x
x y父亲->mp2[y]/2=x
左右 -> mp[y]*2(+1)=x
就行了,注意数值不存在(直接输出0)和负数string转int
Code:
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
const int N = 1e3+7;
struct node{
int val, key;
int left, right, tag=1, p;
}g[N];
map<int,int> mp;
map<int,int> mp2;
int root=1;
int cnt=1, zpx, zpy;
int toint(string s){
int x = 0, tag=1;
int i;
if(s[0]=='-') i=1, tag=-1;
else i=0;
for(;i<s.size();i++){
x = x*10+s[i]-'0';
}
return x*tag;
}
int judge(string s){
int n = s.size();
int i;
int last = 0, tag;
for(i=0;i<n;i++){
if(s[i]==' ') break;
}
zpx = toint(s.substr(0,i));
i++;
last = i;
string s2,s3,s4;
for(i;i<n;i++){
if(s[i]==' ') break;
}
s2 = s.substr(last,i-last);
i++;
last = i;
for(i;i<n;i++){
if(s[i]==' ') break;
}
s3 = s.substr(last,i-last);
if(s2=="and"){
zpy = toint(s3);
return 1;
}
i++;
last = i;
for(i;i<n;i++){
if(s[i]==' ') break;
}
s4 = s.substr(last,i-last);
if(s4=="root") return 0;
else if(s4=="parent") tag=2;
else if(s4=="left") tag=3;
else tag=4;
s4="";
for(i=n-1;i>=0;i--){
if(s[i]==' ') break;
}
s4 = s.substr(i+1,s.size()-i-1);
//if(tag==2) cout<<'\n'<<s4<<'\n';
zpy = toint(s4);
return tag;
}
int main(){
//std::ios::sync_with_stdio(false);
//cin.tie(0);
int n,m,x;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>x;
mp[i]=x;
int zp = i;
while(zp/2>0&&mp[zp]>mp[zp/2]){
swap(mp[zp],mp[zp/2]);
zp/=2;
}
}
for(int i=1;i<=n;i++){
mp2[mp[i]] = i;
//cout<<mp[i]<<' '<<i<<'\n';
}
string s;
getline(cin,s);
while(m--){
getline(cin,s);
//cout<<s;
int tag = judge(s);
if(tag>=1&&(!mp2.count(zpx)||!mp2.count(zpy))){
cout<<0;
continue;
}
if(tag==0){
if(mp[1]==zpx) cout<<1;
else cout<<0;
}
else if(tag==1){
if(mp2[zpx]/2==mp2[zpy]/2) cout<<1;
else cout<<0;
}
else if(tag==2){
if(mp2[zpy]/2==mp2[zpx]) cout<<1;
else cout<<0;
}
else if(tag==3){
if(mp2[zpy]*2==mp2[zpx]) cout<<1;
else cout<<0;
}
else{
if(mp2[zpy]*2+1==mp2[zpx]) cout<<1;
else cout<<0;
}
}
}
第四题
第四题是让你模拟一个车,这个车每次都贪心的从所有点里面选一个没访问过的距离最小的点(距离相同就看节点大小),让你依次输出他经过的节点和行驶总距离
看到题目的时候离考试结束还有 00:45,但当时没啥感觉。。可能真的是绝望了吧,就想做一下吧,做不出来就,也没想这个。。
第四题,我第一次读题以为是一步走到的点里面最近的呢,但是样例一就是推不出来,后来一遍遍读题枚举题意(主要是百思不得其解为什么N那么小),突然一想n^3好像有个floyd,才知道是全部的点。
那就是个非常简单的floyd+dfs了,每次贪心选择最小的点,如果没全部的点都vis过就第二种形式输出
结果WA了->22,为啥啊
原来没看见要是没全部的点,第一行是按照访问顺序的。。
原来。。
改一下就AC了,复杂度O(n^3)(还是PAT只要你复杂度别离谱基本都是A)
Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 507;
typedef long long ll;
ll ans = 0, vis[N];
ll inf = LONG_LONG_MAX;
vector<int> v2;
ll f[207][207];
int cnt = 0;
void dfs(int u,int n){
if(!vis[u]) v2.push_back(u), cnt++;
vis[u]=1;
ll now,val=inf;
for(int i=1;i<=n;i++){
if(u==i||f[u][i]==0||vis[i]==1) continue;
if(f[u][i]<val) now=i, val=f[u][i];
}
if(val!=inf&&cnt<=n+1) ans += val,dfs(now,n);
}
vector<int> v3,v4;
void floid(int n){
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<=n;k++){
if(f[j][i]==0||f[i][k]==0) continue;
if(f[j][k]==0) f[j][k] = f[j][i]+f[i][k];
else f[j][k] = min(f[j][i]+f[i][k],f[j][k]);
}
}
}
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
ll n,m,x,y,w;
cin>>n>>m;
for(int i=0;i<m;i++){
cin>>x>>y>>w;
if(f[x][y]==0){
f[x][y]=w;
f[y][x]=w;
}
else
{
f[x][y]=f[y][x]=min(w,f[x][y]);
}
}
floid(n);
dfs(0,n);
for(int i=0;i<=n;i++){
//if(vis[i]) v3.push_back(i);
if(!vis[i])v4.push_back(i);
}
if(v4.size()!=0){
for(int i=0;i<v2.size();i++){
cout<<v2[i];
if(i!=v2.size()-1) cout<<' ';
else cout<<'\n';
}
for(int i=0;i<v4.size();i++){
cout<<v4[i];
if(i!=v4.size()-1) cout<<' ';
}
}
else{
//memset(vis,0,sizeof vis);
for(int i=0;i<v2.size();i++){
cout<<v2[i];
if(i!=v2.size()-1) cout<<' ';
else cout<<'\n';
}
cout<<ans;
}
}
这里我的blog就写完了,写这篇blog主要是记录自己的心理,提醒自己无论什么时候别慌。。
后记:
感觉自己还是运气比较好的,因为我第三道题一下就A了,没有陷进去,我看到好多99/97都是第三道题有一个点,很可惜。