测试67。好题。数学,打表,fibonacci树规律。
TO:1:打表。
P1: T3为了小点跑得快没取mod。
但是打表的时候忘了加取mod!少了20分。
注意1、检查要把题目要求过一遍。
2、打表注意暴力在大数据点下是否正确。
P2:分块打表。例:以500为块长,%500的部分跑暴力。
要灵活。
2:做题顺序。
1:T2,显然最水的可以先做。
2:T1,T3暴力。
3:T1去想正解。
3:态度。要去尽力拿分,从可能的地方找切入点。
T1:数学题。注意莫比乌斯函数不是联赛考点。
考试时状态不太好,态度不够认真
没想到((x,S)=1)==((x,S-x)==1)。发现一些性质。等效。
1、更换枚举顺序。第一层sigma放到第二层可以O(1)算。Sigma式更换顺序。
2、考虑实际含义。
T2:最简单的。树状数组维护LIS长度及方案数。
T3:fibonacci树。
1、观察规律。一个黑点的第i层子节点中白点个数为fib(i)。
2、等效。斐波那契树的子部分都是等效的。重复部分来源于等效。
这样的话每个等效部分只枚举一次,再乘上等效个数即可。
T1思路整理:n<=1e14->sqrt()
a+b<=n&&(a+b)|ab;
a=d*x,b=d*y;
d*(x+y)|d*d*x*y
(x+y)|d*x*y
And (x,y)==1->x+y|d
Ans=sigma:d(1,n)*x(1,n/d)*y(1,n.d-x),[(x,y)=1,x+y|d]
一种其他思路:d*(1,n)*D*u(D)*x’*y’.
D=gcd(x,y)
但是不可写,是错的。
1、考虑实际含义。2、x+y往往可以变为x,S-x
S=x+y,((x,y)=1)==((x,S)=1)
更相减损可证。
则枚举x,y转化为求ou(S). 把枚举转化为可以预处理或者直接O(1)算的式子,函数。
Ans=sigma:d(1,n)*S(S|d)*ou(S)&&d*S<=n S<d,S*S<=n,S为sqrt级别。
外层O(n),且内层约数sqrt。这个很难做,
分析正解sqrt级别。
更换枚举顺序。发现S<=sqrt(n);
直接变枚举约数为倍数,把S放到前面。
{S*d<=n,S|d}->sigma:d =n/(S^2)
则Ans=sigma:S(1,sqrt(n)*ou(S)*(n/(S^2));
下面是下发题解和我的代码。
#include<bits/stdc++.h> #define F(i,a,b) for(rg int i=a;i<=b;++i) #define LL long long #define rg register #define pf(a) printf("%d ",a) #define phn puts("") using namespace std; #define int LL #define N 10000010 int n,t; LL ans; int prm[N/10],cnt,ou[N]; signed main(){ scanf("%lld",&n); t=sqrt(n); F(i,2,t){ if(!ou[i]){ ou[i]=i-1;prm[++cnt]=i; } for(int j=1;j<=cnt&&i*prm[j]<=t;++j){ if(i%prm[j]==0){ ou[i*prm[j]]=ou[i]*prm[j];break; } else { ou[i*prm[j]]=ou[i]*ou[prm[j]]; } } } F(i,1,t){ ans=(ans+ou[i]*(n/(i*i))); } printf("%lld\n",ans); } /* g++ 1.cpp -g time ./a.out 21 */
#include<bits/stdc++.h> #define F(i,a,b) for(int i=a;i<=b;++i) #define LL long long #define pf(a) printf("%d ",a) #define phn puts("") using namespace std; /** mod*/ #define int LL int n,type; #define N 100500 int a[N]; const int mod=123456789; const int maxn=1e5+10; int w[N],s[N]; int MO(int x){return x<mod?x:x-mod;} void add(int x,int l,int c){ for(;x<=maxn;x+=x&-x){ if(w[x]<l){ w[x]=l;s[x]=c; } else if(w[x]==l){ s[x]=MO(s[x]+c); } } } LL l,c; void ask(int x){ l=0;c=0; for(;x;x-=x&-x){ if(w[x]>l){ l=w[x];c=s[x]; } else if(w[x]==l){ c=MO(c+s[x]); } } } signed main(){ scanf("%lld%lld",&n,&type); F(i,1,n)scanf("%lld",&a[i]); a[n+1]=1e5+1; add(1,0,1); F(i,1,n){ ask(a[i]); add(a[i]+1,++l,c); } ask(a[n+1]); printf("%lld\n",l); if(type)printf("%lld\n",c); } /* g++ 2.cpp -g ./a.out 5 1 1 3 2 5 4 */
#include<cstdio> #include<iostream> #include<vector> #define rg register #define F(i,a,b) for(rg int i=a;i<=b;++i) #define LL long long #define pf(a) printf("%d ",a) #define phn puts("") using namespace std; int n; #define N 200010 const int mod=123456789; LL len[10010]; LL f[N],g[N]; int max(int x,int y){return x>y?x:y;} signed main(){ scanf("%d",&n); f[1]=1;g[1]=1;F(i,2,n)(g[i]=g[i-1]+(f[i]=(f[i-1]+f[i-2])%mod))%=mod; F(i,2,n-1)len[i]=(len[i]+f[i-1]*(g[max(n-i-2,0)]+1))%mod; F(j,2,n-2)len[j+1]=(len[j+1]+f[j-1]*g[n-j-1])%mod; F(i,3,n-2){ F(j,2,n-2){ (len[i+j]+=f[i-2]*f[j-1]%mod*g[n-max(i,j)-1])%=mod; } } F(i,1,n<<1)printf("%lld ",len[i]);phn; } /* g++ 3.cpp -g time ./a.out 20 */