一点点总结:
干了点什么。
关于考试……废在T1上了:-(
T1打了半天表,找了$Theta(Nsqrt{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'
otmid b' \
a'
otmid d \
a'
otmid b'
$$
有
$$a'+b' mid d \ a'+b' otmid a'$$
于是可以直接枚举$a'+b'$来判断合法性。
因为$a+bleq n $且$dgeq 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 ",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 ",res.len); if(typ) printf("%lld ",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(""); }