csp模拟时过了两题,最后一题没过,这里重点说一下
T1-TT数鸭子
题目描述
样例
输入
6 5
123456789 9876543210 233 666 1 114514
输出
4
思路分析
数组vis[10],记录0-9是否在存放当前数的字符串中出现过。判断字符串中每个字符,若当前字符不是已出现过的数字,计数num++,当num大于等于k不合要求。最终输出所有num<k的数。
模测时过了,补题时错了,关掉同步就好了。
AC代码
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
int vis[10];
int main()
{
ios::sync_with_stdio(false);
int n,k;
cin>>n>>k;
int num=0,ans=0;
string str;
for(int i=0;i<n;i++)
{
memset(vis,0,sizeof(vis));
num=0;
cin>>str;
for(int j=0;j<str.size();j++)
{
if(vis[str[j]-'0']==0)//一个新数
{
num++;
vis[str[j]-'0']=1;
}
if(num>=k) break;//不和要求
}
if(num<k) ans++;
}
cout<<ans;
return 0;
}
T2-ZJM要抵御宇宙射线
题目描述
样例
输入
5
0 0
0 1
1 0
0 -1
-1 0
输出
0.00 0.00
1.00
思路分析
这题就是找n个点每个点离得最远点的距离的最小值,对于n个点,先遍历其他点得到距离最远的点,再与当前最远距离的最小值对比,最终得到n个点中最远距离的最小值和对应两个点的索引。
这里要注意数据范围,由于答案是距离的平方,可能超过1e10,所以最大值设置为1e11,并且使用long double。根据题目要求,要先把每个点按x升序,y升序排列。
AC代码
#include<iostream>
#include<cmath>
#include <iomanip>
#include<algorithm>
using namespace std;
struct Point
{
long double x,y;
Point(){}
Point(long double _x,long double _y)
{
x=_x;y=_y;
}
bool operator < (const Point& b) const
{
if(x!=b.x)
{
return x<b.x;
}
return y<b.y;
}
};
Point p[1005];
long double Count(int p1,int p2)
{
long double ans=pow((p[p1].x-p[p2].x),2)+pow((p[p1].y-p[p2].y),2);
return ans;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>p[i].x>>p[i].y;
}
sort(p,p+n);
int Max_p1=0,Max_p2=0;
long double Min=1e11;
for(int i=0;i<n;i++)
{
long double Max=0;
int temp_p2=0;
for(int j=0;j<n;j++)
{
if(i==j) continue;
long double num=Count(i,j);
//cout<<i<<" "<<j<<" "<<num<<endl;
if(num>Max)
{
Max=num;
temp_p2=j;
}
}
//cout<<"Max "<<Max<<endl;
if(Max<Min)
{
Max_p1=i;
Max_p2=temp_p2;
Min=Max;
}
}
cout<<setiosflags(ios::fixed)<<setprecision(2)<<p[Max_p1].x<<" "<<p[Max_p1].y<<endl<<Min;
return 0;
}
T4-宇宙狗的危机
题目描述
样例
样例1解释
思路分析
一开始一直在想怎么建树,然后再判断是否合要求,感觉非常麻烦,模测时也没有写出来,补题时才想到了区间dp的方法。
数组a[]存放递增数据,用GCD[i][j]存放a[i]a[j]的最大公约数。
用f[i][j]表示区间[l,r]内的数能否构成一棵二叉树,还需要涉及它的父节点,它要么是l−1,要么是r+1,因此只需再增加一个 [0/1]就行了,f[i][j][tag] (tag=0/1)。
dp(l,r,0,root) 返回以root为根,[l,r]内的数能否构成右子树;
dp(l,r,1,root) 返回以root为根,[l,r]内的数能否构成左子树.
首先当l>r时,返回true,否则若当前情况已经判断过,返回f[l][r][tag]。for循环遍历,l<=i<=r,当最大公约数GCD[root][i]大于1时,
f[l][r][tag] |=dp(i + 1, r, 0, i) && dp(l, i - 1, 1, i),返回f[l][r][tag]。
Vis[i][j][2]记录当前情况是否判断过,每次判断过则将其置为true。
答案为dp(1,n,0,0)返回的结果。
AC代码
#include<iostream>
#include<string.h>
using namespace std;
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b,a%b);
}
int a[800],GCD[800][800];
bool vis[800][800][2],f[800][800][2];
bool dp(int l,int r,int tag,int root)
{
if(l>r) return true;
if(vis[l][r][tag]) return f[l][r][tag];
vis[l][r][tag] = true;
for (int i = l; i <= r && !f[l][r][tag]; i++)
{
if (!root || GCD[root][i] > 1)
f[l][r][tag] |= dp(i + 1, r, 0, i) && dp(l, i - 1, 1, i);
}
return f[l][r][tag];
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
memset(vis,false,sizeof(vis));
memset(f,false,sizeof(f));
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<= n;i++)
{
for(int j=1;j<=n;j++)
{
GCD[i][j] = gcd(a[i], a[j]);
}
}
if(dp(1,n,0,0)) cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}