最长树链(未解决)
虽然这道题我至今没有过,但是我还是决定先写一个博客来纪念(bushi / 记录)我那悲惨无奈的处境
最开始,我愚蠢地使用二维数组和floyed算法,不过别说运行了,直接变量空间过大,还是经验不足,也没有分析复杂度,即使运行了,也tmd铁定TLE ... 然后就将自己写了比较久的代码全部推翻,所以,在写之前要综合考虑时间和空间的复杂度,不要上来就写,以为写出来就万事大吉了,其实不过是莽撞而已
然后,依然没有分析时间复杂度,自以为是的写了比较好理解的bfs, 呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵, 50% , nice , TLE , 再然后, 就用了枚举素数的方法,用网上的的到素数的方法,一个一个数试,好家伙,并用了树形DP 来求素数对应的那些树组成的森林中的每一棵树的直径,然后求出最大值,好家伙,62.5% , 上帝是让我逼近于成功,但就是不让我成功,这是考验,呵呵
插曲:
看了题解大佬不满足于这水的数据(然鹅现实是我连这水一般的数据都过不了 ... ,,,),用了素性判断,以此来筛选出大素数,于是乎我又用了一段时间去了解米勒拉宾素性判断
中间用到了一些简单知识(不过我低效率的用了比较长的时间):
数论中的拉格朗日定理
余式定理
AKS(确定性的)
不过据ksj大佬说,1e5的数据根本不需要使用素性判断,所以算是仅仅多学了点东西
于是,我又用了素数筛,来求这个森林,学了两个素数筛 , 最后用了线性筛,不过好像没多大用 ... 我又分别用unordered_map and map 分别来试,不过没多大差别(两种map性能比较),最终都是 75%
现在想先放一放,不想这样耗下去了,目前的代码:
//https://ac.nowcoder.com/acm/problem/13233
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOCAL
using namespace std;
const int maxn=1e5+10;
const int INF=1e5;
vector link[maxn];
int val[maxn];
unordered_map> mp;
int dp[maxn]; // 在该树中离这一点最远的距离
int mark[maxn];
int ans=1;
// vector primes;
int primes[maxn];int cont=0;
int isnp[maxn]={0};
int read(){
int s=0,f=1,c=getchar();
while (c<'0' || c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0' && c<='9') { s=s*10+c-'0';c=getchar();}
return s*f;
}
// 先用最简单的埃氏筛 (后来证明不行)
// void getprime(){
// for (int i=2;i<=4e4;++i){
// if (!isnp[i]){
// for (int j=i*i;j<=4e4;j+=i){
// isnp[j]=1;
// }
// primes.push_back(i);
// }
// }
// }
// 然后使用线性筛
// void getprime(){
// for (int i=2;i<=4e4;++i){
// if (!isnp[i]) primes.push_back(i);
// for (int j=0;j<(int)primes.size();++j){
// if (primes[j]*i>4e4) break;
// isnp[i*primes[j]]=1;
// if (i%primes[j]==0) break;
// }
// }
// }
void getprime(){
// int cont=0;
for (int i=2;i<=4e4;++i){
if (!isnp[i]) primes[++cont]=i;
for (int j=1;j<=cont;++j){
if (primes[j]*i>4e4) break;
isnp[i*primes[j]]=1;
if (i%primes[j]==0) break;
}
}
}
//wait
int gcd(int a,int b)
{
while(b^=a^=b^=a%=b);
return a;
}
//quick_pow has mod generally, or it will overflow ; when mod==0 , mod doesn't exist
int quick_pow(int d, int z,int mod){
// if (!z) return 1;
int rs=1;
while(z){
if (z&1) {rs*=d;if (mod) rs%=mod;}
z>>=1;
d*=d;
if (mod) d%=mod;
}
return rs;
}
/*
米勒罗宾素性判断:
(1)计算奇数M,使得N=2^r * M + 1;
(2)选择随机数A>=1;++r;}
for (int i=0;i<5;++i){
int A=rand()%(N-2)+2;
int B=quick_pow(A,M,N);
if (B==1) continue;
for (int i=0;ia;
if(val[u]%num!=0) return 0;
mark[u]=1;int res=1;
for(int x:link[u])
{
if(!mark[x])
{
int Cnt=dp_dfs(x,num);
res=max(res,1+Cnt);
ans=max(ans,res);
a.push_back(Cnt);
}
}sort(a.begin(),a.end());
int x=a.size();
if(x>1) ans=max(ans,a[x-1]+a[x-2]+1);
return res;
}
int main(){
#ifdef LOCAL
freopen("input.txt","r",stdin);
#endif
srand((unsigned int)time(NULL));
getprime();
int n=read();
for (int i=1;i 积
if (miller_rabbin(pdct)) {
mp[pdct].push_back(i);
continue;
}
// for (int j=2;j*j<=pdct;++j){ // 这里可以简化,可以先得到素数表,然后根据表中的素数来遍历查询,因为数越大,素数越离散,浪费的时间越多
// for (int j:primes){
// if (j*j<=pdct){
// if (pdct%j==0){
// while(pdct%j==0) pdct/=j;
// mp[j].push_back(i);
// }
// }
// }
for (int j=1;j<=cont && primes[j]*primes[j]<=pdct;++j){
if (pdct%primes[j]==0){
while(pdct%primes[j]==0) pdct/=primes[j];
mp[primes[j]].push_back(i);
}
}
if (pdct>1) mp[pdct].push_back(i);
}
for (unordered_map>::iterator p=mp.begin();p!=mp.end();++p){
// for (int i=0;i<(int)p->second.size();++i) if (mark[p->second[i]]==0) dp_dfs(p->second[i],p->first);
for (int j:p->second) if (mark[j]==0) dp_dfs(j,p->first);
// for (int i=0;i<(int)p->second.size();++i) mark[p->second[i]]=0;
for (int j:p->second) mark[j]=0;
}
// printf("%d",ans+1);
printf("%d",ans);
return 0;
}
-----------------------------------10-11-------------------------------------------