千钧一发-双十
一点点总结:
干了点什么。
关于考试……废在T1上了:-(
T1打了半天表,找了$\Theta(N\sqrt{N})$的方法,得了少的可怜的$40$
T2感受出了$dp$和线段树的味道但是只是打了个暴力。
T3打个暴力丟上去骗了点分。
要做什么。
先看看三道题……这回忘了看把我搞死了。
不重要的:找规律想想$\phi(x)$
有了什么。
|
32
|
Miemeng | 40
03:07:34
|
40
03:07:34
|
40
03:07:34
|
120
03:07:34
|
黄唧唧的分数……
题解(差点咕掉
T1
不打表了,试图用题解的法子证一证。(完全是在口胡,可以看这个大神的:%%%)
首先点对满足
$$a+b \mid ab$$
我们记$a$和$b$的$gcd$为$d$
有:
$$(a'+b')d \mid a'b' d^2$$
于是约去一个$d$
$$a'+b' \mid a'b' d$$
因为
$$
a' \not\mid b' \\
a' \not\mid d \\
a' \not\mid b'
$$
有
$$a'+b' \mid d \\ a'+b' \not\mid a'$$
于是可以直接枚举$a'+b'$来判断合法性。
因为$a+b\leq n $且$d\geq a'+b'$
于是在每个$a'+b'\leq \sqrt{n}$下只有$\phi(a'+b')$个合法解
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#define LL long long
#define sqN 11111111
using namespace std;
int phi[sqN];
bool not_p[sqN];
vector<int> prm;
LL ans,n;
void prerun(){//getphi
const int lim=10000000;
phi[1]=0;
for(int i=2;i<=lim;i++){
if(!not_p[i]){
prm.push_back(i);
phi[i]=i-1;
}
for(int j=0;j<prm.size();j++){
if(i*prm[j]>lim)break;
not_p[i*prm[j]]=1;
if(i%prm[j]==0){
phi[i*prm[j]]=phi[i]*prm[j];
break;
}
else phi[i*prm[j]]=phi[i]*(prm[j]-1);
}
}
}
int main(){
// freopen("1.in" ,"r",stdin);\
freopen("2.out","w",stdout);
prerun();
scanf("%lld",&n);
for(LL i=1;i*i<=n;i++)
ans+=n/(i*i)*phi[i];
printf("%lld\n",ans);
}
T2
线段树优化$dp$,可以直接二元组$dp$出结果。
#include <iostream>
#include <cstring>
#include <cstdio>
#define N 111111
#define LL long long
using namespace std;
const int Mod=123456789,maxR=100011;
struct DP{
int len;
LL ans;
DP(){len=ans=0;}
DP(int a,LL b):len(a),ans(b){}
};
struct XDS{
int l,r;
DP dat;
#define lc(k) ((k)<<1)
#define rc(k) ((k)<<1|1)
}rt[N*4];
int rn,typ,arr[N];
DP Max(const DP &a,const DP &b){
if(a.len>b.len)return a;
if(a.len<b.len)return b;
return DP(a.len,(a.ans+b.ans)%Mod);
}
void build(int k,int l,int r){
rt[k].l=l,rt[k].r=r;
rt[k].dat=DP(0,0);
if(l==r)return ;
int mid=(l+r)/2;
build(lc(k),l ,mid);
build(rc(k),mid+1,r);
}
void change(int k,int id,DP v){
if(rt[k].l==rt[k].r){
rt[k].dat=Max(rt[k].dat,v);
return ;
}
int mid=(rt[k].l+rt[k].r)>>1;
if(mid>=id)
change(lc(k),id,v);
else
change(rc(k),id,v);
rt[k].dat=Max(rt[lc(k)].dat,rt[rc(k)].dat);
}
DP query(int k,int l,int r){
if(l<=rt[k].l && rt[k].r<=r)
return rt[k].dat;
DP nw;
int mid=(rt[k].l+rt[k].r)>>1;
if(mid>=l)
nw=Max(nw,query(lc(k),l,r));
if(mid<r)
nw=Max(nw,query(rc(k),l,r));
return nw;
}
int main(){
// freopen("1.in" ,"r",stdin );\
freopen("1.out","w",stdout);
scanf("%d%d",&rn,&typ);
for(int i=1;i<=rn;i++){
scanf("%d",arr+i);
arr[i]++;
}
build(1,1,maxR);
for(int i=1;i<=rn;i++){
DP fw=query(1,1,arr[i]-1);
change(1,arr[i],Max(DP(fw.len+1,fw.ans),DP(1,1)));
}
DP res=query(1,1,maxR);
printf("%d\n",res.len);
if(typ)
printf("%lld\n",res.ans);
}
T3
Fibonacci树……
分$LCA$枚举长度统计答案$\Theta(N^2)$
#include <iostream>
#include <cstring>
#include <cstdio>
#define N 5555
#define LL long long
using namespace std;
const int Mod=123456789;
LL dep,pre[N],fib[N],ans[N*2];
int main(){
scanf("%lld",&dep);
fib[1]=1,fib[2]=0;
for(int i=3;i<=dep;i++)
fib[i]=(fib[i-1]+fib[i-2])%Mod;
for(int i=1;i<=dep;i++)
pre[i]=(pre[i-1]+fib[i])%Mod;
for(int i=1;i<dep;i++)
ans[i]=(pre[dep-i]*fib[i+1])%Mod;
for(int i=1;i<=dep;i++){
for(int j=1;j<=dep;j++){
int h=max(i,j);
ans[i+j]+=((pre[dep-h+1]-1)*fib[i]%Mod*fib[j+1]%Mod)%Mod;
ans[i+j]%=Mod;
}
}
for(int i=1;i<=2*dep;i++)
printf("%lld ",ans[i]);
puts("");
}
Miemeng真的蒻

浙公网安备 33010602011771号