【PAT】必拿下的逻辑题

逻辑题

【例】A1148 Werewolf - Simple Version (20 分)

partition v.划分;分割
werewolf n.狼人

ATTENTION

  • 太悲伤了这道题TAT 模拟的时候被彻底绕进去了 结果一看柳神解答 “水题” … 太扎心了呜呜呜QAQ
  • 一开始想的是遍历所有说假话的人,但一直纠结怎样才能找出所有的狼人,因为虽然可以对假话取反,但这并不代表n句话说明了所有人的身份,最后的判断好难模拟orz
  • 后来看了柳神的解答! 哦!太妙了!!!如果先把所有人假设成好人,再遍历两个狼人,那就是在确定了所有人的身份以后再根据他们说的话确定谁在说假话!!!妙哉妙哉~~ (柳神好会这种技巧啊www 好几道题感觉都是这个套路 出奇制胜
  • 等判断出了谁在说假话后,再判断这两个说假话的是不是一个好人一个狼人,如果是的话!那就是结果了!【注意!我是遍历了所有的狼人,所有最后输出狼人的时候就不用去看谁是负数了,直接输出外层循环变量i和j就行了!!!】
  • abs头文件:#include <algorithm>abs只能求整数的绝对值。
  • 浮点数的绝对值要用fabs(头文件:#include <cmath>
  • 学到了很多 (这场模拟死的超级惨orz 不知道一个月后的PAT会不会…
#include <iostream>
#include <vector>
#include <algorithm> 	//abs头文件 
using namespace std;

int n;
int id[110]={1};
int num[110];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>num[i];
	for(int i=1;i<n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			fill(id+1,id+n+1,1);
			id[i]=-1;id[j]=-1;
			
			vector<int> ans;
			for(int k=1;k<=n;k++)
			{
				if(num[k]*id[abs(num[k])]<0)
						ans.push_back(k);
			}
			if(ans.size()==2&&id[ans[0]]*id[ans[1]]<0)
			{
				cout<<i<<" "<<j<<endl;
				return 0;
			}
		}
	}
	cout<<"No Solution\n";
}

【例】A1093 Count PAT’s (25 分)

ATTENTION

  • 这道题十分钟就过了呜哇哇哇,太爽了!!!(虽然过了,但其实自己思路还没很清晰…
  • 假设一个P后面所有"AT"的组合个数为tmp,那么这个P所能组合成的"PAT"的个数就是tmp。同理,假设一个A后面所有的T的个数为cntT,那么这个A所能组合成的"AT"的个数就是cntT。所以,从后往前遍历,当遇到T时,cntT++;当遇到A时,tmp+=cntT;当遇到P时,ans+=tmp
  • 柳神的做法:关注A。对于每一个A,它前面的P的数量×它后面的T的数量就是这个A能构成的PAT的个数。 因为它后面的T的数量很难与其他操作同步,所以先计算出所有T的数量,然后顺序遍历,每遇到一个T,就-1。
  • 记得取模!每一步都要取模!!!
#include <iostream>
#include <string>
#include <vector>
using namespace std;

string str;
vector<int> idx[100010];
int cntT=0,tmp=0,ans=0;

int main()
{
	cin>>str;
	for(int i=str.size()-1;i>=0;i--)
	{
		if(str[i]=='T')
			cntT++;
		if(str[i]=='A')
			tmp+=cntT;
		if(str[i]=='P')
		{
			ans+=tmp;
			ans=ans%1000000007; 
		}
	}
	cout<<ans%1000000007;
	return 0;
}

【例】A1128 N Queens Puzzle (20 分)

diagonal adj. 斜的;对角线的;斜纹的
configuration n. 配置;结构;外形

ATTENTION

  • 英语问题。啧,虽然但是,隐约记得是斜对角线,为什么不试一下呢??? 白瞎3分。
  • 最近做题总是有点超时,要多注意复杂度。
  • 假设机器1s执行108。这道题数据规模最大为1000,200个case,200×1000×1000=1e8,所以不做一些提前判断很容易超时。
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;

int k,n,pos[1010];
int vis[1010];

int main()
{
	scanf("%d",&k);
	while(k--)
	{
		scanf("%d",&n);
		fill(vis+1,vis+n+1,0);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&pos[i]);
			vis[pos[i]]++;
		}
			
		bool flag=true;
		for(int i=1;i<=n;i++)
			if(vis[i]!=1) flag=false;
		for(int i=1;i<=n;i++)
		{
			for(int j=i+1;j<=n;j++)
			{
				if(j!=i&&abs(j-i)==abs(pos[j]-pos[i]))
				{
					flag=false;
					break;
				}	
			}
		} 
		if(!flag) printf("NO\n");
		else printf("YES\n");
	}
}

【例】A1125 Chain the Ropes (25 分)

fold v. 折叠
figure n. 数字;人物;图形;
halved v. (使)减半;对半分(halve 的过去式和过去分词)

ATTENTION

  • 因为最后只取整数,所以用floor函数。

round(x,m):对浮点数进行四舍五入,可以设置保留m位小数,默认是零。
floor():返回不大于给定数的最接近整数,舍去小数部分取整。
ceil():返回不小于给定数的下一个整数。

  • 【注】printf("%.0f")四舍五入(%后边为几都是),一般要求精确到m位都可以用printf。
  • 这道题用优先队列模拟pushpop也能做,sort模拟会超时。
  • sort的复杂度不够优秀,sort超时时可以尝试set和priority_queue
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

int n;
bool cmp(double &a,double &b){return a>b;}

int main()
{
	scanf("%d",&n);
	vector<double> seg(n);
	for(int i=0;i<n;i++)
		scanf("%lf",&seg[i]);
	sort(seg.begin(),seg.end(),cmp);
	double sum=0.0;
	for(int i=0;i<seg.size();i++)
	{
		if(i==seg.size()-1||i==seg.size()-2)
		{
			int j=n-1;
			while(j--)
				seg[i]=seg[i]/2;
		}
		else
		{
			int j=i+1;
			while(j--)
				seg[i]=seg[i]/2;
		}
		sum+=seg[i];
	}
	printf("%.0f",floor(sum));
	return 0;
}

priority_queue

#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;

int n;

int main()
{
	scanf("%d",&n);
	priority_queue<double,vector<double>,greater<double> > q;
	for(int i=0;i<n;i++)
	{
		double tmp;
		scanf("%lf",&tmp);
		q.push(tmp);
	}
	double sum=0.0;
	while(q.size()>=2)
	{
		double a=q.top();
		q.pop();
		a+=q.top();
		q.pop();
		a/=2;
		q.push(a);	
	}
	sum=q.top();
	q.pop();
	sum+=q.top();
	sum/=2;
	printf("%.0f",floor(sum));
	return 0;
}

【例】A1124 Raffle for Weibo Followers (20 分)

raffle vi. 抽彩
give away 赠送;丧失;泄露
generate vt. 使形成;发生;生殖;产生物理反应
current candidate 当前的候选人

ATTENTION

  • 题意:从转发的第s个人开始,每抽一个就跳过n个,如果当前这个人已经被抽过了,就再跳过一个。
  • 所以理所当然的,会在s的基础上模拟。一个一个的遍历就是愚蠢,还容易错T^T
  • 这算得上是建模失败了其实。其实也可以说是题意理解不透彻。正式考试的时候思维上不要偷懒。用什么做法更合乎计算机逻辑更合乎题意就用什么做法。
  • 这种第一题,能设点方便操作的变量就多设点,反正第一题肯定不会超内存,大气点。
#include <iostream>
#include <string>
#include <set>
#include <vector>
using namespace std;

int m,n,s;
string name[1010];
vector<string> res;

int main()
{
	cin>>m>>n>>s;
	for(int i=1;i<=m;i++)
		cin>>name[i];
	if(s>m)
	{
		cout<<"Keep going...\n";
		return 0;
	}	
	set<string> distinct;
	int cnt=1;
	while(cnt<=m)
	{
		if(cnt==s)
		{
			int size=distinct.size();
			distinct.insert(name[cnt]);
			if(size!=distinct.size())
			{
				res.push_back(name[cnt]);
				s+=n;
			}
			else s++;
		}
		cnt++;
	}
	for(int i=0;i<res.size();i++)
	{
		if(i==0) cout<<res[i];
		else cout<<"\n"<<res[i];
	}
	return 0;
}

【例】A1109 Group Photo (25 分)

formation n.编队;形成;构造
rear n.后方
duplication n.复制;副本

ATTENTION

  • round(double x,m)
    头文件:#include <cmath>

  • 不要再纠结个别测试点了TAT啊啊啊啊啊啊!!!!什么嘛这套卷子第一题太搞心态了啊!!!!!

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstdlib>
using namespace std;
 
int n,k;
struct PER{
	string name;
	int tall;
}per[10010];

bool cmp(PER &a,PER &b)
{
	if(a.tall==b.tall)
		return a.name<b.name;
	return a.tall>b.tall;
}
int main()
{
	cin>>n>>k;
	for(int i=0;i<n;i++)
		cin>>per[i].name>>per[i].tall;
	sort(per,per+n,cmp);
	int cntPerRow=round(n*1.0/k);
	int last=n-cntPerRow*(k-1);
	int cnt,idx=0;
	for(int i=1;i<=k;i++)
	{
		if(i==1) cnt=n-cntPerRow*(k-1);
		else cnt=cntPerRow;
		vector<int> tmp(cnt+1);
		int t=0,s=1;
		while(t<cnt)
		{
			int c=round(cnt/2+1);
			if(t==0)
			{
				tmp[c]=idx++;
				t++;
			}
			if(t==cnt) break;
			tmp[c-s]=idx++;
			t++;
			if(t==cnt) break;
			tmp[c+s]=idx++;
			t++;
			s++;
		}
		for(int j=1;j<tmp.size();j++)
		{
			if(j==1) cout<<per[tmp[j]].name;
			else cout<<" "<<per[tmp[j]].name;
		}
		cout<<"\n";
	}
}

【例】A1108 Finding Average (20 分)

partition v.划分;分割
werewolf n.狼人

ATTENTION

  • 笑死最近第一题总是炸。
  • 这道题自己的写法还有两分怎么也过不去,先存个档。
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;

int main()
{
	int n,cnt=0;
	char a[50],b[50];
	double tmp,sum=0.0;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		scanf("%s",a);
		sscanf(a,"%lf",&tmp);
		sprintf(b,"%.2f",tmp);
		//printf("%s %s\n",a,b);
		int flag=0;
		for(int j=0;j<strlen(a);j++)
			if(a[j]!=b[j]) flag=1;
		if(flag||tmp<-1000||tmp>1000)
		{
			printf("ERROR: %s is not a legal number\n",a);
			continue;
		}
		else
		{
			sum+=tmp;
			cnt++;
		}
	}
	if(cnt == 1)
		printf("The average of 1 number is %.2f", sum);
	else if(cnt > 1)
		printf("The average of %d numbers is %.2f", cnt, sum / cnt);
	else
		printf("The average of 0 numbers is Undefined");
	return 0;
}

18分

#include <cstdio>
#include <string>
#include <iostream>
using namespace std;

int n,cnt=0;
double sumInt=0,sumFra=0;
string str;

int main()
{
	scanf("%d",&n);
	bool flag=true;
	for(int i=0;i<n;i++)
	{
		flag=true;
		cin>>str;
		if(str[0]=='-')
		{
			for(int j=1;j<str.size();j++)
			{
				if((str[j]<='9'&&str[j]>='0')||str[j]=='.') continue;
				else{
					flag=false;
					break;
				}
			}
		}
		else if(str[0]=='.')
		{
			for(int j=1;j<str.size();j++)
			{
				if(str[j]<='9'&&str[j]>='0') continue;
				else{
					flag=false;
					break;
				}
			}
		}
		else if(str[0]<='9'&&str[0]>='0')
		{
			for(int j=0;j<str.size();j++)
			{
				if((str[j]<='9'&&str[j]>='0')||str[j]=='.') continue;
				else{
					flag=false;
					break;
				}
			}
		}
		else flag=false;
		if(!flag)
		{
			printf("ERROR: %s is not a legal number\n",str.c_str());
			continue;
		}
		int pos=str.find(".");
		int pos2=str.find(".",pos+1);
		if(pos2!=string::npos||(pos!=string::npos&&str.size()-pos>3))
		{
			printf("ERROR: %s is not a legal number\n",str.c_str());
			continue;
		}
		if(str=="-."||str=="."||str=="-")
		{
			printf("ERROR: %s is not a legal number\n",str.c_str());
			continue;
		}
		if(pos==string::npos)
		{
			int num=atoi(str.c_str());
			if(num>1000||num<-1000) flag=false;
			else
			{
				sumInt+=num;
				cnt++;
			}	
		}
		else
		{
			int numI=atoi(str.substr(0,pos).c_str());
			int numF=atoi(str.substr(pos+1,str.size()-pos-1).c_str());
			if(str.substr(pos+1,str.size()-pos-1).size()==1) numF*=10;
			double tmp=numI*1.0;
			if(str[0]=='-') numF=-numF;
			tmp+=numF*1.0/100;
			if(tmp>1000||tmp<-1000) flag=false;
			else
			{
				sumInt+=numI;
				sumFra+=numF;
				cnt++;
			}
		}
		if(!flag)
		{
			printf("ERROR: %s is not a legal number\n",str.c_str());
			continue;
		}
	}
	if(cnt==0)
		printf("The average of 0 numbers is Undefined\n",cnt);
	else if(cnt==1)
		printf("The average of 1 number is %.2f\n",sumInt+sumFra/100);
	else
		printf("The average of %d numbers is %.2f\n",cnt,(sumInt+sumFra/100)/cnt);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值