感覺自己代碼能力好弱啊
T1 完全k叉樹
傳送門
Solution
首先特判一下K=1K=1K=1
然后處理出最大滿KKK叉樹,設(shè)這棵樹的深度為rankrankrank,根節(jié)點(diǎn)的深度為000,這個(gè)時(shí)候的答案,就是2?rank2*rank2?rank
如果還有剩下的節(jié)點(diǎn),顯然如果答案可以擴(kuò)大為2?rank+12*rank+12?rank+1
現(xiàn)在已經(jīng)考慮了深度小于等于rankrankrank的點(diǎn)互相匹配 and 深度為rank+1rank+1rank+1與深度小于等于rankrankrank的點(diǎn)配對的情況。
還有一種情況就是深度為rank+1rank+1rank+1的點(diǎn)相配對,如果要使答案變大,則匹配的兩個(gè)點(diǎn)的lcalcalca必須是根節(jié)點(diǎn)(太好證了,請自行證明),處理出根節(jié)點(diǎn)的最左邊兒子在rank+1rank+1rank+1層需要多少個(gè)節(jié)點(diǎn)才能填滿,與剩下的節(jié)點(diǎn)判斷一下大小就好了。
#include<iostream>
using namespace std
;
typedef long long ll
;
ll
getSize(ll K
,ll rk
){ll ret
= 1;ll cur
= 1;for(int i
=1;i
<=rk
;i
++){cur
*= K
;ret
+= cur
;}return cur
;
}
void solve(){ll K
,N
;cin
>>K
>>N
;if(K
==1){cout
<<N
-1<<endl
;return;}ll cur
= 1;ll rank
= 0;ll tmp
= N
-1;while(tmp
>= cur
* K
){rank
++;tmp
-= cur
* K
;cur
*= K
;}if(rank
==0){if(N
==2){cout
<<1<<endl
;return;}else{cout
<<2<<endl
;return;}}ll ans
= (rank
<<1);if(tmp
== 0){cout
<<ans
<<endl
;return;}ans
= max(rank
*2+1,ans
);ll pre
= tmp
/ K
;if(tmp
% K
)pre
++;ll ned
= getSize(K
,rank
-1);if(pre
> ned
){ans
= max(rank
*2+2,ans
);}cout
<<ans
<<endl
;}
int main(){ios
::sync_with_stdio(0);int T
;cin
>>T
;while(T
--){solve();}return 0;
}
T2 距離產(chǎn)生美
傳送門
Solution
發(fā)現(xiàn)最大可以把數(shù)字修改成101810^{18}1018而KKK最大才10910^9109
也就是說,修改過一個(gè)數(shù)之后,這個(gè)數(shù)的前后兩個(gè)數(shù)與當(dāng)前這個(gè)數(shù)肯定能滿足題意
就可以dpdpdp了
設(shè)f[i][0]f[i][0]f[i][0]為前iii個(gè),第iii個(gè)沒修改,f[i][1]f[i][1]f[i][1],為前iii個(gè),第iii個(gè)修改了的最小值
轉(zhuǎn)移,直接看代碼
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
const int MAXN
= 200000;
int n
,k
,data
[MAXN
],f
[MAXN
][2];
int Abs(int x
){return x
>0?x
:-x
;
}
int main(){ios
::sync_with_stdio(0);cin
>>n
>>k
;for(int i
=1;i
<=n
;i
++)cin
>>data
[i
];for(int i
=1;i
<=n
;i
++){if(i
==1){f
[i
][1]=1;}else{if(Abs(data
[i
]-data
[i
-1])>=k
){f
[i
][0]=min(f
[i
-1][0],f
[i
-1][1]);f
[i
][1]=min(f
[i
-1][0],f
[i
-1][1])+1;}else{f
[i
][0]=f
[i
-1][1];f
[i
][1]=min(f
[i
-1][0],f
[i
-1][1])+1;}}}cout
<<min(f
[n
][0],f
[n
][1]);return 0;
}
T3 烤面包片
傳送門
Solution
注意特判N=0N=0N=0和mod=0mod=0mod=0的時(shí)候
剩下的可以發(fā)現(xiàn)nnn在很小的時(shí)候n!!!n!!!n!!!就比10910^9109大了
就可以暴力了
細(xì)節(jié)看代碼
#include<iostream>
using namespace std
;
typedef long long ll
;
ll n
,mod
;
ll
ksc(ll a
,ll b
,ll p
){ll ret
= 0;while(b
){if(b
&1){ret
= (ret
+a
)%p
;}a
= (a
*2)%p
;b
>>=1;}return ret
;
}
int main(){ios
::sync_with_stdio(0);cin
>>n
>>mod
;if(mod
==1){cout
<<0;return 0;}if(n
==0){cout
<<1;return 0;}ll cur
= 1;for(ll i
=n
;i
>=1;i
--){double tmp
= cur
;tmp
*= i
;cur
*= i
;if(tmp
>=mod
){cout
<<0;return 0;}}n
= cur
;cur
= 1;for(ll i
=n
;i
>=1;i
--){double tmp
= cur
;tmp
*= i
;cur
*= i
;if(tmp
>=mod
){cout
<<0;return 0;}}n
= cur
;cur
= 1;for(ll i
=n
;i
>=1;i
--){cur
= ksc(cur
,i
,mod
);}cout
<<cur
;return 0;
}
T4 茶顏悅色
傳送門
Solution
把yyy和y?ky-ky?k離散化
然后對xxx排序用掃描線
對于一個(gè)點(diǎn)可以發(fā)現(xiàn)它對底邊在[y?k,y][y-k,y][y?k,y]的正方形有貢獻(xiàn)
用線段樹維護(hù)貢獻(xiàn)值,相當(dāng)于區(qū)間加減和查詢?nèi)肿畲笾?/p>
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+10;
int n,k;
struct _{int x,y;
};
_ data[MAXN];
int buf[MAXN],tot,tr[MAXN<<3],tag[MAXN<<3];
void pushup(int x){tr[x]=max(tr[x<<1],tr[x<<1|1]);}
void pushdown(int x){tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];tr[x<<1] += tag[x]; tr[x<<1|1] += tag[x]; tag[x]=0;
}
void Modify(int rt,int l,int r,int L,int R,int delta){pushdown(rt);int mid=(l+r)>>1;if(l==L&&r==R){tag[rt]=delta;tr[rt]+=delta;return;}if(R<=mid)Modify(rt<<1,l,mid,L,R,delta);else if(L>mid)Modify(rt<<1|1,mid+1,r,L,R,delta);else{Modify(rt<<1,l,mid,L,mid,delta);Modify(rt<<1|1,mid+1,r,mid+1,R,delta);}pushup(rt);
}
bool cmp(_ a,_ b){return a.x<b.x;}
int main(){ios::sync_with_stdio(0);cin>>n>>k;for(int i=1;i<=n;i++){cin>>data[i].x>>data[i].y;buf[++tot]=data[i].y;buf[++tot]=data[i].y-k;}sort(buf+1,buf+1+tot);tot=unique(buf+1,buf+1+tot)-buf-1;sort(data+1,data+1+n,cmp);int l=1,ans=0;for(int i=1;i<=n;i++){int L=lower_bound(buf+1,buf+1+tot,data[i].y-k)-buf,R=lower_bound(buf+1,buf+1+tot,data[i].y)-buf;while(data[l].x+k<data[i].x){Modify(1,1,tot,lower_bound(buf+1,buf+1+tot,data[l].y-k)-buf,lower_bound(buf+1,buf+1+tot,data[l].y)-buf,-1);l++;}Modify(1,1,tot,L,R,1);ans=max(ans,tr[1]);}cout<<ans;return 0;
}
T5 飛行棋
傳送門
Solution
正著不好做就倒著做,設(shè)起點(diǎn)為111,終點(diǎn)為d+1d+1d+1
設(shè)f[i]f[i]f[i]為從終點(diǎn)走到點(diǎn)iii的期望步數(shù),則f[1]f[1]f[1]就是最后的答案
因?yàn)樽詈蟮?span id="ze8trgl8bvbq" class="katex--inline">K+1K+1K+1個(gè)節(jié)點(diǎn)非常煩,可以直接高斯消元求出來(我求出來才發(fā)現(xiàn)有規(guī)律……)
然后對于一個(gè)不在最后K+1K+1K+1個(gè)節(jié)點(diǎn)之內(nèi)的點(diǎn)
有
∑j>i且i+k>=jf[j]/K+1=f[i]\sum_{j>i且i+k>=j}{f[j]/K}+1=f[i]j>i且i+k>=j∑?f[j]/K+1=f[i]
就可以矩陣快速冪了,那個(gè)+1+1+1可以單獨(dú)開一維保存常數(shù)
細(xì)節(jié)看代碼
#include<bits/stdc++.h>
using namespace std
;
typedef long long ll
;
const int MAXK
= 25;
const int MOD
=1e9+7;
ll
Exgcd(ll a
,ll b
,ll
&x
,ll
&y
){if(b
==0){x
=1;y
=0;return a
;}ll d
=Exgcd(b
,a
%b
,y
,x
);y
-=a
/b
*x
;return d
;
}
ll
GetInv(ll x
){ll a
,b
;Exgcd(x
,MOD
,a
,b
);return (a
+MOD
)%MOD
;
}
void update(ll
&x
){x
%=MOD
;x
=(x
+MOD
)%MOD
;
}
ll k
,d
,dishu
;
ll data
[MAXK
][MAXK
];
struct Mar
{ll a
[MAXK
][MAXK
];Mar(){memset(a
,0,sizeof a
);}void clear(){memset(a
,0,sizeof a
);}
};
Mar
operator * (Mar x
,Mar y
){Mar c
;for(int i
=1;i
<=k
;i
++){for(int j
=1;j
<=k
;j
++){for(int h
=1;h
<=k
;h
++){c
.a
[i
][j
]=(c
.a
[i
][j
]+(x
.a
[i
][h
]*y
.a
[h
][j
])%MOD
)%MOD
;}}}return c
;
}
void Gauss(){ll n
= k
+1;data
[n
][n
]=1;for(int i
=1;i
<n
;i
++){for(int j
=1;j
<=k
;j
++){int toward
= i
+j
;if(toward
> n
){toward
= n
- (toward
- n
);}data
[i
][toward
] += dishu
;data
[i
][n
+1] -= dishu
;update(data
[i
][toward
]);update(data
[i
][n
+1]);}data
[i
][i
]--;update(data
[i
][i
]);} for(int i
=1;i
<=n
;i
++){if(data
[i
][i
]==0)continue;ll inv
= GetInv(data
[i
][i
]);for(int j
=1;j
<=n
+1;j
++){data
[i
][j
]=(data
[i
][j
]*inv
)%MOD
;}for(int j
=1;j
<=n
;j
++){if(data
[j
][i
]==0 || i
==j
)continue;ll D
= data
[j
][i
];for(int h
=1;h
<=n
+1;h
++){data
[j
][h
] = (data
[j
][h
] - data
[i
][h
]*D
)%MOD
;update(data
[j
][h
]);}}}
}int main(){ios
::sync_with_stdio(0);cin
>>d
>>k
;dishu
= GetInv(k
);Gauss();if(d
==k
){cout
<<data
[1][k
+2];return 0;}Mar Init
; Init
.clear();for(int i
=k
;i
>=1;i
--){Init
.a
[1][k
-i
+1] = data
[i
][k
+2];}k
++;Init
.a
[1][k
] = 1;d
-= (k
-1);Mar Trans
; Trans
.clear();for(int i
=1;i
<k
-1;i
++){Trans
.a
[i
+1][i
]=1;}for(int i
=1;i
<k
;i
++){Trans
.a
[i
][k
-1]=dishu
;}Trans
.a
[k
][k
-1]=1;Trans
.a
[k
][k
]=1;Mar I
; I
.clear();for(int i
=1;i
<=k
;i
++)I
.a
[i
][i
]=1;while(d
){if(d
&1){I
=I
*Trans
;}Trans
=Trans
*Trans
;d
>>=1;}Init
= Init
* I
;cout
<<Init
.a
[1][k
-1];return 0;
}
T6 三元組
傳送門
Solution
發(fā)現(xiàn)那個(gè)不等式只可能有兩種成立方式
2(ai+aj)<=bi+bj2(a_i+a_j)<=b_i+b_j2(ai?+aj?)<=bi?+bj?
2(bi+bj)<=ai+aj2(b_i+b_j)<=a_i+a_j2(bi?+bj?)<=ai?+aj?
這兩種方式是不可能同時(shí)成立的(證明很顯然,不證了)
可以分別統(tǒng)計(jì)
把第一個(gè)式子分離一下有
2ai?bi<=bj?2aj2a_i-b_i<=b_j-2a_j2ai??bi?<=bj??2aj?
顯然可以分治或者離散化一下隨便找個(gè)數(shù)據(jù)結(jié)構(gòu)維護(hù)
第二種情況把a,ba,ba,b互換再做一次就好了
我不是知道我那根神經(jīng)抽了,寫的分治
#include<bits/stdc++.h>
using namespace std
;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
const int MOD
= 1e9+7;
const int MAXN
= 1e5+2;
typedef long long ll
;
struct _
{ll a
,b
,c
,v1
,v2
;int loc
;
};
_ data
[MAXN
],data2
[MAXN
];
int n
;
void Build(){rep(i
,1,n
){data
[i
].v1
=2*data
[i
].a
-data
[i
].b
;data
[i
].v2
=-data
[i
].v1
;}
}
void Read(){cin
>>n
;rep(i
,1,n
){cin
>>data
[i
].a
>>data
[i
].b
>>data
[i
].c
;data
[i
].loc
=i
;}
}
_ buf
[MAXN
];
ll ans
;
void DAC(int l
,int r
){int mid
=(l
+r
)/2;if(l
==r
){if(data
[l
].v1
<=data
[l
].v2
){ans
= (ans
+ (data
[l
].c
*data
[l
].c
)%MOD
)%MOD
;}return;}DAC(l
,mid
);DAC(mid
+1,r
);int R
= r
;ll cur
= 0;for(int i
=mid
;i
>=l
;i
--){while(R
>=mid
+1 && data
[i
].v1
<= data2
[R
].v2
){cur
= (cur
+ data2
[R
].c
)%MOD
;R
--;}ans
= (ans
+ (cur
* data
[i
].c
)%MOD
)%MOD
;}int p1
=l
,p2
=mid
+1,tot
=l
;while(p1
<=mid
||p2
<=r
){if(p1
<=mid
&&p2
<=r
){if(data
[p1
].v1
< data
[p2
].v1
){buf
[tot
++]=data
[p1
++]; }else{buf
[tot
++]=data
[p2
++];}}else if(p1
<=mid
){buf
[tot
++]=data
[p1
++];}else{buf
[tot
++]=data
[p2
++];}}rep(i
,l
,r
)data
[i
]=buf
[i
];p1
=l
;p2
=mid
+1;tot
=l
;while(p1
<=mid
||p2
<=r
){if(p1
<=mid
&&p2
<=r
){if(data2
[p1
].v2
< data2
[p2
].v2
){buf
[tot
++]=data2
[p1
++];}else{buf
[tot
++]=data2
[p2
++];}}else if(p1
<=mid
){buf
[tot
++]=data2
[p1
++];}else{buf
[tot
++]=data2
[p2
++];}}rep(i
,l
,r
)data2
[i
]=buf
[i
];
}
bool cmp(_ x
,_ y
){return x
.loc
< y
.loc
;
}
int main(){ios
::sync_with_stdio(0);Read();Build();rep(i
,1,n
)data2
[i
]=data
[i
];DAC(1,n
);sort(data
+1,data
+1+n
,cmp
);rep(i
,1,n
)swap(data
[i
].a
,data
[i
].b
);Build();rep(i
,1,n
)data2
[i
]=data
[i
];DAC(1,n
);cout
<<ans
;return 0;
}
T7 籃球校賽
傳送門
Solution
狀壓dpdpdp板子題,直接上代碼
#include<bits/stdc++.h>
using namespace std
;
typedef long long ll
;
const int MAXN
= 1e5+2;
ll f
[MAXN
][1<<5];
ll n
,data
[MAXN
][6];
int main(){ios
::sync_with_stdio(0);cin
>>n
;for(int i
=1;i
<=n
;i
++){for(int j
=1;j
<=5;j
++){cin
>>data
[i
][j
];}}for(int i
=1;i
<=n
;i
++){for(int s
=1;s
<(1<<5);s
++){f
[i
][s
] = -0x3f3f3f3f3f3f3f3fLL;}}for(int i
=1;i
<=n
;i
++){for(int s
=1;s
<(1<<5);s
++){f
[i
][s
] = max(f
[i
][s
],f
[i
-1][s
]);for(int j
=0;j
<5;j
++){if(s
&(1<<j
)){f
[i
][s
] = max(f
[i
-1][s
^(1<<j
)]+data
[i
][j
+1],max(f
[i
][s
],f
[i
-1][s
]));}}}}cout
<<f
[n
][(1<<5)-1];return 0;
}
T8 分配學(xué)號
傳送門
Solution
可能是我計(jì)數(shù)能力太弱了,我感覺這是最難的一道題。
首先最后的完成的序列排序后一定是由一段又一段連續(xù)的數(shù)構(gòu)成的,不然沒法保證次數(shù)最小。
所以排序后從小到大貪心。
如果能構(gòu)成一段連續(xù)的數(shù)那就不管,如果不行就要開始改變學(xué)號。
現(xiàn)在只考慮一段需要修改成一段連續(xù)的數(shù)的序列
比如1,1,1,11,1,1,11,1,1,1
又貪心
最后一定是
1,2,3,41,2,3,41,2,3,4
總的代價(jià)等于最后的代數(shù)和-最初的代數(shù)和,所以只需要給最初的序列進(jìn)行排列,然后依次賦值就行了。
可是題目還有一個(gè)條件是,修改后的學(xué)號一定要變大。
那么對于這樣一段序列,我們對每個(gè)數(shù)減去(第一個(gè)數(shù)-1),化成以數(shù)值1開頭的序列a[i]a[i]a[i]。
這樣問題就變成了
問有多少個(gè)排列b[i]b[i]b[i],使得一個(gè)數(shù)jjj在b[i]b[i]b[i]中的位置大于等于a[j]a[j]a[j]
用插空法計(jì)數(shù),設(shè)f[i]f[i]f[i]為前iii個(gè)數(shù)的答案
f[i]=f[i?1]?(i?a[i]+1)f[i] = f[i-1]*(i-a[i]+1)f[i]=f[i?1]?(i?a[i]+1)
意思是第iii個(gè)數(shù)最靠前可以插在原來第a[i]a[i]a[i]個(gè)數(shù)的前面,讓它的排名至少為a[i]a[i]a[i],
然后一共有iii個(gè)位置。
說了這么多,代碼卻那么短
#include<bits/stdc++.h>
using namespace std
;
typedef long long ll
;
const int MOD
= 1e9+7;
const int MAXN
= 1e5+2;
int n
;
ll data
[MAXN
];
int main(){ios
::sync_with_stdio(0);cin
>>n
;for(int i
=1;i
<=n
;i
++){cin
>>data
[i
];}sort(data
+1,data
+1+n
);ll ans
= 1;for(int j
,i
=1;i
<=n
;i
=j
){for(j
=i
+1;j
<=n
&&data
[j
]<data
[i
]+j
-i
;j
++){ans
= ans
* (data
[i
]+j
-i
-data
[j
]+1) % MOD
;} }cout
<<ans
;return 0;
}
T9 Gree的心房
傳送門
Solution
很容易發(fā)現(xiàn)答案的下界是n+m?2n+m-2n+m?2,走最上面一行和最右邊一列。
然后障礙物最多有(n?1)?(m?1)(n-1)*(m-1)(n?1)?(m?1)個(gè)。
#include<iostream>
using namespace std
;
typedef long long ll
;
ll n
,m
,k
;
int main(){cin
>>n
>>m
>>k
;if(k
>((n
-1)*(m
-1))){cout
<<-1;}else{cout
<<n
-1+m
-1;}return 0;
}
總結(jié)
以上是生活随笔為你收集整理的CCPC-Wannafly Comet OJ 夏季欢乐赛(2019)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。