一上一下的蓝名。。何时能稳定下来。。
第一次终测挂了一道题排名居然还上升了。。。总之这一场就是fst+hack专场吧。。。
A:给你一个字符串,求是否有一个字母出现超过2次。(注意:n=1要特判yes,否则WA)出题人还算良心卡掉了没判1的情况,不然就好玩了。。。
B:这是本套题最坑的题,给你n对数,让你求是否存在一个数,对于每对数,都存在1个数或者2个数能整除他。
n为1.5e5,a[i]高达2e9。所以想提前筛因子是不可能的。
hack点1:x,y要加入答案数组中。有一些人初始化只加了x和y的非1因子,却没加x和y,最终fst test 14
hack点2:有些人企图用set等保存所有数的因子再O(n)判断,然后 fst tle 45。数高达2e9,如果每一对数都拥有很多个因子,显然复杂度再乘上一个n就瞬间爆炸。
正解(我看到的一个比较好的解法)应该是 先预处理每一对数的LCM。(因为答案肯定是这些lcm的某个因子),然后对每一对数的lcm求gcd。这就是初始的答案ans。然后再O(n)扫一遍,如果这一对数有能整除ans的数就不管,否则就从gcd(ans,a[i])和gcd(ans,b[i])中取一个最大的替换ans。总时间复杂度为O(nlogn)。
C:给你一个wb串,你可以选任意一个位置,将这个位置两边的串翻转再接起来。问你最后最长的wbwbw这样间隔的长度是多长。这个题比较偏向思维。在纸上画一下发现一次操作就相当于在这个串后面再接上这个串。于是把这个串再复制一遍接到后面,然后就求一个最大的wbwb串即可。注意:
hack点1:只有w或b的时候答案为1,有的人没判被我hack了一个
hack点2:不要想着去模拟,我造了个wwwwb有个代码答案是4,然后就被我hack了。光判情况能过终测的概率太小了。
hack点3:如果按照我这个思路,最后答案一定不要忘了和n取最小值!!!我刚开始忘了,通过比赛数据后突然想起来了立马改了,最后才过了终测。
D:这道题也比较坑。给你一些数,求是否能用这些数构成二叉搜索树,而且每个边连接的两个节点gcd大于1。
有9页的终测挂在了这组数据:
4
2 3 5 30
原因就是没想着构造树或者构造的时候只考虑了整体的gcd数或者构造方法不正确。还有一些未知的原因代码太长我就没看。。。
其实记忆化搜索即可(区间dp)。
dp[l][r][2]。若第三维为0,表示区间[l,r] 作为上一个节点的左孩子。1就表示[l,r] 作为上一个节点的右孩子。然后预处理能够连接的下标。
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=710;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int n,m,k;
int y[maxn][maxn];
int c[maxn],dp[maxn][maxn][2];
int ans,ct,cnt,tmp,flag;
bool jud(int l,int r,int id)
{
if(l>r)return 1;
int &ans=dp[l][r][id];
if(ans+1) return ans;
ans=0;
int up=id?l-1:r+1;
for(int i=l;i<=r;i++)
if(y[i][up]&&jud(l,i-1,0)&&jud(i+1,r,1))
return ans=1;
return ans;
}
int main()
{
int T,cas=1;
while(scanf("%d",&n)!=EOF)
{
memset(dp,-1,sizeof(dp));
for(int i=0;i<n;i++)
{
scanf("%d",&c[i]);
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(gcd(c[i],c[j])>1){
y[i][j]=1;
}
for(int i=0;i<n;i++)
if(jud(0,i-1,0)&&jud(i+1,n-1,1))
return puts("Yes"),0;
puts("No");
//printf("%d\n",ans);
//if(flag) puts("Yes"); else puts("No");
}
return 0;
}