FJUT2019暑假周赛三部分题解
Posted xenny
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FJUT2019暑假周赛三部分题解相关的知识,希望对你有一定的参考价值。
A本来想改到q<1e5,让你们预处理的,然后想了哈作为个逆元模板题吧= =,做不出来自行反思。
B贴个题面
因为只有一次机会,那么也就是两点分布期望E = p了,先说说大家的做法,先求出每个n的逆元保存,然后因为最大只会取到1e6,所以对0-1e6跑一遍每个数的倍数个数。复杂度O(N1/3),代码如下
1 #include <iostream> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1000000; 5 ll sum[maxn+1]; 6 ll sqr3(ll n) 7 int l=0,r=maxn+1; 8 while(l+1<r) 9 ll mid = (l+r)>>1; 10 if(mid*mid*mid>n) 11 r=mid; 12 else l=mid; 13 14 return l; 15 16 void exgcd(const ll a, const ll b, ll &g, ll &x, ll &y) 17 if (!b) g = a, x = 1, y = 0; 18 else exgcd(b, a % b, g, y, x), y -= x * (a / b); 19 20 21 ll inv(const ll num,const ll MOD) 22 ll g, x, y; 23 exgcd(num, MOD, g, x, y); 24 return ((x % MOD) + MOD) % MOD; 25 26 ll fast_mult(ll x,ll y,ll mod) 27 ll tmp=(x*y-(ll)((long double)x/mod*y+1.0e-8)*mod); 28 return tmp<0 ? tmp+mod : tmp; 29 30 int main() 31 for(ll i=1;i<=maxn;i++) 32 sum[i]=sum[i-1]+((i+1)*(i+1)*(i+1)-1)/i-(i*i*i-1)/i; 33 34 int T; 35 cin>>T; 36 while(T--) 37 ll n,mod; 38 cin>>n>>mod; 39 ll temp=sqr3(n); 40 ll ans=sum[temp-1]+n/temp-(temp*temp*temp-1)/temp; 41 ans=fast_mult(ans%mod,inv(n,mod)%mod,mod); 42 cout<<ans<<endl; 43 44 return 0; 45
然后我的做法是
这里对每一步做一个解释 = =,大佬可以略过,[S]代表艾弗森约定,就是S为真则值为1,否则值为0。
对于第一个等号,就是求这些赢点的个数和。
对于第二个等号,用x来代表k的立方根的底。
对于第三个等号,第一个艾弗森约定应该不难理解,底肯定会小于等于原值。
对于第四个等号,这里第一个和式是处理边界,这里x=N的立方根的底(写错了,懒得重新改了)。这部就是把边界单独处理了。
对于第五个等号,讨论y的取值。
对于第六个等号,换底,然后是对y求和.
后面的同上,讨论取值求和。
最后就可以求得一个公式,因为要求立方根的底,建议用牛顿迭代求解。
最终的复杂度就是O(QlogN)。代码如下
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int q; 5 ll n,Mod,w; 6 double newton(double x) 7 double x1, x2; 8 if (x == 0.0) return 0.0; 9 x1 = x; 10 x2 = (2.0 * x1 + x / (x1 * x1)) / 3.0; 11 while (fabs((x2 - x1) / x1) >= 1E-6) 12 x1 = x2; 13 x2 = (2.0 * x1 + x / (x1 * x1)) / 3.0; 14 15 return x2; 16 17 18 void extgcd(ll a,ll b,ll& x,ll& y) 19 if(!b) 20 x = 1; 21 y = 0; 22 return ; 23 24 extgcd(b,a%b,y,x); 25 y -= x*(a/b); 26 27 28 ll inverse(ll a,ll n) 29 ll x,y; 30 extgcd(a,n,x,y); 31 return (x+n)%n; 32 33 34 ll qmul(ll a,ll b) 35 ll ans = 0; 36 while (b) 37 if (b&1) 38 ans = (ans+a)%Mod; 39 40 a = (a+a)%Mod; 41 b >>= 1; 42 43 return ans; 44 45 46 void solve() 47 cin >> n >> Mod; 48 ll k = newton(n); 49 ll w = n/k - 3; 50 if (k&1) 51 w += k*k/2 + 5*k/2 + 1; 52 else 53 w += k/2*k + k/2*5; 54 55 //cout << k << ‘ ‘ << w << endl; 56 ll ans = qmul(w%Mod,inverse(n,Mod)); 57 cout << ans << endl; 58 59 60 int main() 61 ios_base::sync_with_stdio(0); 62 cin >> q; 63 while (q--) 64 solve(); 65 66 return 0; 67
太伤心了= =,被离线算法吊打。
以上是关于FJUT2019暑假周赛三部分题解的主要内容,如果未能解决你的问题,请参考以下文章
区间最小值 线段树 ( JXNU_ACS 算法组暑假第一次周赛)