CC. Minimize the Thickness
Sample input
4
6
55 45 30 30 40 100
4
10 23 7 13
5
10 55 35 30 65
6
4 1 1 1 1 4
Sample output
3
4
2
3
题意:
给你一个长度为n的数组a,你可以将数组a划分为很多个段,每段之和相同,问你所有划分方式中的最大分段长度的最小值是多少
思路:
可以枚举第一个分段到了哪一个位置,然后这个和就出来了,然后对后面的数进行二分,复杂度就是O(nlog(n)),下面看代码把
#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
int n,a[N],mx;
long long s[N];
bool dfs(int u,int len){
if(u > n) return true;
int l = u,r = n,ans = -1;
while(l <= r){
int mid = l + r >> 1;
if(s[mid] - s[u-1] >= len) ans = mid,r = mid - 1;
else l = mid + 1;
}
if(ans == -1 || s[ans] - s[u-1] != len) return false;
mx = max(mx,ans-u+1);
return dfs(ans+1,len);
}
void solve(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),s[i] = s[i-1] + a[i];
int res = n;
for(int i=1;i<=n;i++){
long long cnt = s[i] - s[0];
int l = i + 1,r = n,ans = -1;
mx = i;
if(!cnt || (s[n]-s[i])%cnt){
continue;
}
if(dfs(i+1,cnt)) res = min(res,mx);
}
printf("%d\n",res);
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
D. Masha and a Beautiful Tree
Sample input
4
8
6 5 7 8 4 3 1 2
4
3 1 4 2
1
1
8
7 8 4 3 1 2 6 5
Sample output
4
-1
0
-1
题意:
给你一棵完全二叉树,这棵树的所有叶子节点有n个,组成了一个排列,你可以进行一次操作将具有相同父节点的两个节点交换位置,问你最少需要多少次交换能使得这n个叶节点形成一个1-n的排列
思路:
首先看第一步,一定是先换两两相邻的兄弟节点,而且这两个兄弟节点如果相差不为1这棵树就无解,先把所有的叶子节点换成兄弟两个顺序正确,然后发现可以将两个节点归成一个,继续进行这个操作,把这个新归成的节点就是他们的除以二上取整 ,然后最后归成1就结束了,下面看代码把
#include<bits/stdc++.h>
using namespace std;
void solve(){
int n;
scanf("%d",&n);
vector<int> b[30];
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
b[0].push_back(x);
}
long long ans = 0;
for(int k=0;k<30;k++){
if(b[k].size() == 1) break;
for(int i=0;i<b[k].size();i+=2){
if(abs(b[k][i]-b[k][i+1]) != 1){
puts("-1");
return;
}
ans += b[k][i] > b[k][i+1];
b[k+1].push_back((b[k][i]+1)/2);
}
}
printf("%lld\n",ans);
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
E. Sending a Sequence Over the Network
Sample input
7
9
1 1 2 3 1 3 2 2 3
5
12 1 2 7 5
6
5 7 8 9 10 3
4
4 8 6 2
2
3 1
10
4 6 2 1 9 4 9 3 4 2
1
1
Sample output
YES
YES
YES
NO
YES
YES
NO
题意:
给你一个长度为n的数组,你需要将这个数组分成若干段,每一段的前面或者后面必须有一个值表示这一段的长度,暂且叫这个数为标签吧,作为标签的数就不能出现在任何区间里面,问你有没有一种划分方法满足上述题意
思路:
f[i]表示的是第1-i个数能不能划分出来,然后转移的话就是第i个数作为左标签,第i个数作为右端点这两个,代码很简单,下面看代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
typedef long long LL;
LL f[N];
int a[N];
void solve(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i] = 0;
f[0] = 1;
for(int i=1;i<=n;i++){
if(f[i-1] && i+a[i] <= n) f[i+a[i]] = 1;
if(i>a[i] && f[i-a[i]-1]) f[i] = 1;
}
puts(f[n]?"YES":"NO");
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}