HackerRank Week of Code 26
好像這次week of code不是很難= =
A
int main(){int n;int m;cin >> n >> m;cout<<(n+1)/2*int((m+1)/2)<<"\n";return 0; }B
求n的因數(shù)中數(shù)字和最大的前提下最小的數(shù),n<=10^5,大模擬。
int n; pii qwq; int main() {scanf("%d",&n);for(int i=1;i<=n;i++){if(n%i) continue; int cur=0;for(int j=i;j;j/=10) cur+=j%10;qwq=max(qwq,pii(cur,-i));}printf("%d\n",-qwq.se); }C
求[n,m]之間的孿生素數(shù)對數(shù),1<=n,m<=10^9,m-n<=10^6。
暴力rabin-miller好像卡不過去= = 只要用根號m以內(nèi)的素數(shù)來篩就行。
bool rp[2333333]; int main() {int n,m;scanf("%d%d",&n,&m);for(int s=2;s*s<=m;s++){int g=n/s;for(int p=g*s;p<=m;p+=s){if(p>=n&&p>s) rp[p-n]=1;}}if(n<=1) rp[1-n]=1; int qwq=0;for(int j=n+2;j<=m;j++){if(!rp[j-n]&&!rp[j-n-2]) ++qwq;}printf("%d\n",qwq); }D
有n個點把數(shù)軸分成了n+1段,要求選出一段長度為m的線段使得經(jīng)過的每一段長度在hmin~hmax之間,輸出任意一個起始點,保證有解。n<=10^6,輸入都是1e9范圍。
如果hmin<=m<=hmax的話特判一發(fā),否則可以發(fā)現(xiàn)左右端點一定與某一個點重合,二分找到段的位置,注意細節(jié)...
這題好像數(shù)據(jù)比較弱,部分錯誤做法也能過(我也不知道我交的第一發(fā)是怎么過的= =)
下面這個應該是對的(拍過)
#define SZ 2333333 int n; ll a[SZ],h1,h2,m; bool safe(int x) {return h1<=a[x+1]-a[x]&&a[x+1]-a[x]<=h2; } int qzs[SZ]; void chk(int i,int r) {//cout<<i<<","<<r<<"chk\n";if(i>=r||i<0||r<0||r>n||i>n) return;//cout<<i<<","<<r<<"chk2\n";if(qzs[r-1]-qzs[i]!=r-i-1) return;//cout<<i<<","<<r<<"chk3\n";int s=m-(a[r]-a[i+1]);ll l1=h1,r1=min(h2,a[i+1]-a[i]);ll l2=h1,r2=min(h2,a[r+1]-a[r]);//cout<<l1<<","<<r1<<" "<<l2<<","<<r2<<" "<<s<<"\n";if(l1<=r1&&l2<=r2);else return;int l=max(s-r2,l1),R=min(s-l2,r1);if(l>R) return;cout<<a[i+1]-l<<"\n";exit(0); } //(a[i],a[i+1]] int bl(int x) {return lower_bound(a+1,a+1+n,x)-a-1; } int main() {scanf("%d",&n);a[n+1]=1e13; a[0]=-1e13;for(int i=1;i<=n;i++) scanf("%lld",a+i);scanf("%lld%lld%lld",&m,&h1,&h2);for(int i=0;i<n;i++) qzs[i]=(i?qzs[i-1]:0)+safe(i);if(h1<=m&&m<=h2){puts("1000000000");return 0;}for(int i=0;i<n;i++){int bx;bx=bl(a[i+1]-1-m); chk(bx,i);bx=bl(a[i+1]-m); chk(bx,i);bx=bl(a[i+1]+1-m); chk(bx,i+1);bx=bl(a[i]+m); chk(i-1,bx);bx=bl(a[i]+1+m); chk(i,bx);bx=bl(a[i]-1+m); chk(i-1,bx);}puts("-233333333"); }E
給出一個整數(shù)n,求正整數(shù)對(a,b) (a<b)的對數(shù)使得x*a+y*b=n,x、y為正整數(shù)。n<=30W。
我們考慮對于一個a,枚舉x*a,然后對于y*b判一下n-x*a。
那么問題來了,一個a可能會被算多次。
我們有一個簡單粗暴的方式,把這些a全記下來unique一下。
然后好像跑的挺快的就過了[滑稽]
所以說我們要相信玄學
int n; vector<int> tt[300005]; bool rs[300005]; int main() {ll qwq=0;scanf("%d",&n);for(int i=1;i<=n;i++){vector<int> rp;for(int j=i;j<=n;j+=i){vector<int>& cc=tt[n-j];for(int g:cc) rp.pb(g);}for(int g:rp) rs[g]=1;for(int g:rp) qwq+=rs[g], rs[g]=0;for(int j=i;j<=n;j+=i) tt[j].pb(i);}printf("%lld\n",qwq); }我們來講講道理,前30W個數(shù)平均有15.9385個因數(shù),這樣做的復雜度大致就是225*30W,應該還是很快的 [滑稽]
題解好像十分奧妙重重,看不懂啊= =
F
求sin(x)+sin(y)+sin(z)的最大值,x+y+z=n且x、y、z均為正整數(shù),n<=3000000,顯然是弧度制。
我們假裝x+y=s,那么z=n-s。
sin(x)+sin(y)=sin(x)+sin(s-x)=sinx+sinscosx-cosssinx=sinx(1-coss)+cosxsins
我們用一下輔助角公式,令α=atan(sins/(1-coss)),那么sin(x)+sin(y)就等于K*sin(x+α)(K是多少就不管了)
sin(g)最大就是讓|g-pi/2|最大(當然這里的g要被限制在[0,2pi]),sin(x+α)最大就是讓|x+a-pi/2|最大,就是讓x與pi/2-a最接近,我們把所有滿足條件的x插到map里去,查詢一下相鄰的兩個就行了。
我們從大到小枚舉z,然后s是遞增的,所以x的上限也是遞增的,把這些x一個一個插進去然后在map里查詢就行了。
尷尬的是這樣是300W*log(300W)的,會被卡常。我們考慮假裝z是最小的,就變成100W*log(300W)了,再結合一些優(yōu)秀的卡常技巧就可以卡過= =
注意因為要保留九位小數(shù),只能把x、y、z帶入原式算不然就會炸精度。
int p; ld pi=acos(-1); map<ld,int> ss; ld st2(ld x) {if(x<0) x+=pi+pi;if(x>=pi+pi) x-=pi+pi;return x; } int main() {scanf("%d",&p);pair<ld,int> minn,maxn;minn.fi=1e233; maxn.fi=-1e233;ld ans=0;int upm=min(p/3+1,p-2);int g=1;for(int x=p-2;x>=1;x--){int n=p-x;while(g*(pi+pi)<=n-1) ++g;ld cc=n-1-(g-1)*(pi+pi);minn=min(minn,make_pair(cc,n-1));maxn=max(maxn,make_pair(cc,n-1));ss[cc]=n-1;if(x<=upm){//sinx(1-cosn)+cosx*sinnld g=st2(atan(sin(n)/(1-cos(n))));ld mx=max(sin(minn.se)+sin(n-minn.se),sin(maxn.se)+sin(n-maxn.se));ld r=st2(-g+pi/2);//min|x-r|auto aa=ss.lower_bound(r);if(aa==ss.end());else mx=max(mx,sin(aa->se)+sin(n-aa->se));if(aa==ss.begin());else{--aa;mx=max(mx,sin(aa->se)+sin(n-aa->se));}ld cur=mx+sin(x);if(cur>ans) ans=cur;}}printf("%.9lf\n",ans); }當然既然敢出300W肯定有線性做法= =
官方題解不知道高到哪里去了,首先把sin(x)+sin(y)改寫成2*sin((x+y)/2)*cos((x-y)/2),然后從2~n-1枚舉x+y,顯然z已經(jīng)確定了,那么就只要查詢最大的cos((x-y)/2)就行了。
(很難看出)如果從x+y=s變成x+y=s+2只會多出兩種x-y,例如:
我猜接下來的事情就不用我說了...分奇偶遍歷的時候順便更新最大值即可。
int n; int main() {scanf("%d",&n);ld mi=0,ans=0;for(int s=2;s<n;s+=2){//x+y=s max{x-y}=s-2mi=max(mi,cos((s-2)/2));ans=max(ans,2*sin(s/2)*mi+sin(n-s));}mi=0;for(int s=3;s<n;s+=2){//x+y=s max{x-y}=s-2mi=max(mi,cos((s-2)/2.0));ans=max(ans,2*sin(s/2.0)*mi+sin(n-s));}printf("%.9lf\n",ans); }G
題面和nim游戲有關,大概就是求n個[1,2^m)之間不同的數(shù)使異或和不為0(考慮順序),模1e9+7輸出。n,m<=10^7。
不會做...官方題解大概是這樣的。
記i堆異或和為0的方案數(shù)為fi,那么:
$f_i=A(2^m-1,i-1)-f_{i-1}-(i-1)*(2^m-1-(i-2))*f_{i-2}$
A(x,y)就是x個元素選y個排列的方案數(shù)。官方題解這個公式打錯了
是不是感覺這個公式有了就做完了呢?[生無可戀]
以下是講道理環(huán)節(jié)。
首先我們考慮異或和不為0,這個簡單,A(2^m-1,i-1),隨便選i-1個不同的排在前面,最后一個就是它們的異或和。
然后我們考慮異或完之后肯定是在[0,2^m)之內(nèi)的,但是這個0要扣掉,顯然這前i-1個元素異或完為0的方案數(shù)就是f[i-1]。
尷尬了,現(xiàn)在重復了。那么什么情況會重復呢?顯然我們選出來的前i-1個元素是兩兩不同的,那么只可能這個異或和和之前的元素重復了。那么除掉這個重復的元素,剩下i-2個元素異或和就要為0!這兩個元素必須和剩下的i-2個元素不同,那就是有2^m-1-(i-2)種權值,前i-1個元素都可能充當這個重復元素,那么(i-1)*(2^m-1-(i-2))*f[i-2]就可以得到這部分了。
顯然0不可能和之前的元素重復,那么都扣掉就行了。
int n,m; ll MOD=1e9+7; ll qp(ll a,ll b) {a%=MOD;ll aa=1;while(b){if(b&1) aa=aa*a%MOD;a=a*a%MOD; b>>=1;}return aa; } #define SZ 23333333 ll a[SZ],f[SZ]; int main() {scanf("%d%d",&n,&m);ll tot=qp(2,m)-1;a[1]=tot;for(int i=2;i<=n;i++)a[i]=a[i-1]*(tot-i+1)%MOD;f[0]=1;for(int i=2;i<=n;i++)f[i]=(a[i-1]-f[i-1]-(i-1)*(tot-(i-2))%MOD*f[i-2]%MOD)%MOD;ll ans=a[n]-f[n];ans=(ans%MOD+MOD)%MOD;printf("%lld\n",ans); }轉(zhuǎn)載于:https://www.cnblogs.com/zzqsblog/p/6138977.html
總結
以上是生活随笔為你收集整理的HackerRank Week of Code 26的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java多线程解读一(基础篇)
- 下一篇: [转]Ubantu vmware too