这个博客不再更新,新博客地址请戳
体验1:
军神太强啦,1小时屯6题,瞬间AK,接下来的90分钟一直在跟榜
体验2:
A题原题,循环写得好就不麻烦,不然要写很多行,情况要想全并不难。
B题原题,有了上一场的提示之后,这题就不难了。
C题很简单(小声)。
D题卡掉了O(TNK*log(N))的方法,卡掉我5发logN ,不过还是可做。
E题水dp(组合数学)。
F题原题,记忆化搜索。
体验3:
被DC两题卡到,认识到自己是个菜鸡选手。
D:
一开始写O(NN)的预处理 + map存答案
改成O(NKlogN)的二分查找
再灵机一动想到了O(NK)的做法
有惊无险
C:
一开始看成了卡特兰数,后来发现不对
没带笔纸,找学霸借了笔和纸后开始推公式
发现规律后一顿猛敲,然而蜜汁wa
结束后发现自己循环边界写错了
再也不贪图方便擅自改循环边界了
体验4:
难度较上一场而言,难题偏简单,简单题偏难,很适合我这种菜鸡选手。
懒得说了,直接上题解吧。
由于172.22.112.249/exam进不去,看不到题面了
A
题意:给一个44的矩阵,外圈的格子可以旋转,每次转动1格,求最大22的小矩阵和。
思路:暴力。
#include
using namespace std;
int main(){
int t;cin>>t;
int a[20];
int b[]={6,7,10,11};
int bg[]={1,2,3,4,8,12,16,15,14,13,9,5};
while(t--){
for(int i=1;i<=16;i++)cin>>a[i];
int ans=a[6]+a[7]+a[10]+a[11];
for(int i=0;i<4;i++){
for(int j=0;j<12;j++){
ans = max(ans , a[bg[(j)%12]]+a[bg[(j+1)%12]]+a[bg[(j+2)%12]]+a[b[i]]);
}
}
for(int i=0;i<12;i++){
ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[6] + a[7]);
ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[11] + a[7]);
ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[10] + a[11]);
ans = max(ans , a[bg[(i)%12]]+a[bg[(i+1)%12]] + a[6] + a[10]);
}
cout<
B
题意:找到最小的b,使得n在b进制下,数位上出现的每个数字的次数都相等。
思路:已知一定有解,不妨暴力枚举。
#include
using namespace std;
typedef long long ll;
ll n;
bool check(ll a,ll b){
int vis[65]={0};
while(a){
vis[a%b]++;
a/=b;
}
int v=-1;
for(int i=0;i<65;i++){
if(v==-1){
if(vis[i])v=vis[i];
} else {
if(vis[i] && vis[i]!=v)return 0;
}
}return 1;
}
int main(){
int t;cin>>t;
while(t--){
cin>>n;
for(int b=2;;b++){
if(check(n,b)){
cout<
C
题意:n个点的SB树有多少种(对1e9+7取模)?
思路:
首先我们枚举0到10的所有情况,发现:
n h[n]
0 1
1 1
2 2
3 1
4 4
5 4
6 4
7 1
8 8
9 16
10 32
做这种题,我喜欢先猜结论,再证明正确性。
画图的时候(这里没有图,要图自己画),我们发现这棵树最底层是可以活动的,
而所有非底层都要填满,所以对于2-1,4-1,8-1,这些值,答案一定为1。
那么我们就可以求出最底层有多少个可以活动的点。
因为要保持平衡,假设有rest个可以活动的点,那么我可以左边放rest/2个,剩余的放在右边。
这样我们发现,如果rest/2 != rest - rest/2的话,左右两棵树可以交换,所以结果还要*2。
那么可以在O(N)的复杂度下,算出前n项的结果。
其实可发现,rest/2对应的那棵树,跟前面算出来的树有着相同的分类方法。
自己画图体会吧
#include
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
int main(){
ll h[1050];
h[0]=1;
for(int i=1;i<=1000;i++){
int l=i/2,r=(i-1)/2;
if(l==r)
h[i]=h[l]*h[r]%mod;
else h[i]=2*h[l]*h[r]%mod;
}
int t;cin>>t;
while(t--){
int n;cin>>n;
cout<
D
题意:给一个序列a,给k次查询,每次给一个s,问有多少个区间[l,r],使得区间和等于s。
思路:
首先想到了O(N^2)求出所有的s,然后map记录下来,N=1e4 ,明显要超时。
然后想到对于k个查询,每次都遍历左边界,通过前缀和二分的方式找到右边界,
如果左边界到右边界这一段的和为s,答案+1,复杂度O(KNlogN)
还能把这个logN去除掉,用到的是类似于滑动窗户的方法。复杂度O(K*N)
#include
using namespace std;
template
inline void read(T &ret){
ret=0;
char c=getchar();
while(c>'9'||c<'0')c=getchar();
ret = ret*10+c-48;
while(c=getchar(),c>='0'&&c<='9'){
ret=ret*10+c-48;
}
}
int pre[10005];
int n,k,s,ans;
int a[10005];
int main(){
int t;read(t);
while(t--){
read(n);read(k);
pre[0]=0;
for(int i=1;i<=n;i++){
read(a[i]);
pre[i]=pre[i-1]+a[i];
}
while(k--){
read(s);
ans=0;
int l=1,r=1;
while(l<=n&&r<=n){
if(pre[r]-pre[l-1]==s){
ans++;
l++;r++;
}
else if(pre[r]-pre[l-1]>s){
l++;
} else {
r++;
}
}
cout<
E
题意:问有多少种到达(n,0)的波形。
思路:
很直观的dp,或者用组合数也能做,仁者见仁。
首先到达(0,0)的方法有1种。
到达(x,y)的方法有多少种呢,(x-1,y),(x-1,y-1),(x-1,y+1)都能到达(x,y)
种类数满足加法原理。
#include
using namespace std;
typedef long long ll;
int main(){
ll dp[110][110];
int t;cin>>t;
while(t--){
memset(dp,0,sizeof dp);
int n;cin>>n;
dp[0][0+50]=1;
for(int x=1;x<=n;x++){
for(int y=2;y<=100;y++){
dp[x][y]=max(dp[x][y],dp[x-1][y]+dp[x-1][y-1]+dp[x-1][y+1]);
}
}
cout<
F:
原题,这篇博客里有。
https://blog.csdn.net/mmingfunnytree/article/details/78806763
写的不对的地方欢迎指正,转载请注明出处^ ^.