给一个串,从头尾各切一段下来(也可以不切),问头+尾能否组成"CODEFORCES"。对头尾进行匹配分别得到长度,然后长度相加看是否>=10。
给一个数,问这个数最少能用多少个只包含0和1的数相加得到,输出任意解(数都是十进制)。贪心,但是要注意,设当前还需要凑cur,不能去找最大的不超过cur的只含01的数。比如20,如果减去11,剩下部分还要9个1。。远不如10+10。正确做法是按位来看,如果某一位大于0,那么该位填1,否则填0。
爬山,每天海拔只能和前一天一样或增减1。给出总共爬的天数,记录下了某些天的海拔,问最高可能到达海拔。和之前的一场CF的某题几乎一样。。设相邻两个记录相距d(i+1)-d(i)天,高度为h(i)和h(i+1),中间可到达最大高度就是(d(i+1)-d(i)+h(i)+h(i+1))/2。第一个记录前和最后一个记录后让它逐天递增1就好,找出最大。
在n*n的棋盘上,有个(dx,dy)的集合,定义了当棋子在(x,y)可以跳到(x+dx,y+dy)。给出一个棋盘,上面放了若干棋子,标出了这些棋子能跳到的所有位置。现在(2*n-1)*(2*n-1)的棋盘中心有一枚棋子,要求在上面画出(dx,dy)集合(任意解)。
我的做法是暴力。对每一个(dx,dy),用棋盘上所有棋子去验证这个(dx,dy)是否可行。
一棵树,有m个叶子,所有叶子标有号1~m。两个人轮流从根开始往下走,走到叶子结束。先手希望走到的叶子号尽可能大,后手希望尽可能小,两个人都是最优决策。问先手安排叶子号和后手安排叶子号时,走到的结果分别是什么。
这题目出得好,我弄了很久才理解。首先假设树的所有叶子号我们都已经知道。定义MAX(u)是希望最大的人先手u为根的子树会走到的结果,MIN(u)是希望最小的人先手u为根的子树会走到的结果。vi是u的孩子,那么,MAX(u)就等于MIN(vi)中的最大值,MIN(u)就等于MAX(vi)中的最小值。
但是,树的叶子号我们不知道(可以安排)。只考虑子树中每个叶子的相对大小,就是在子树中所有叶子的rank(从大到小依次1,2,3...)。记f(u)为希望最大的人先行动u子树得到的rank,g(u)为希望最小的人先行动u子树得到的rank。那么对于叶子有f(u)=g(u)=1,非叶子有f(u)=min(g(vi)),g(u)=sum(f(vi))。最后结果就是m-f(1)+1,g(1)(因为对称性)。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int INF=1e9;
int n;
int head[maxn];
int pre[maxn];
int to[maxn];
int f[maxn];
int g[maxn];
int tote;
void addedge(int u,int v){
to[tote]=v;
pre[tote]=head[u];
head[u]=tote++;
}
static int leafcnt=0;
void dfs(int u){
f[u]=INF;
for(int i=head[u];~i;i=pre[i]){
int v=to[i];
dfs(v);
if(g[v]<f[u])f[u]=g[v];
g[u]+=f[v];
}
if(!g[u]){
leafcnt++;
g[u]=f[u]=1;
}
}
int main(){
memset(head,-1,sizeof(head));
tote=0;
cin>>n;
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
dfs(1);
cout<<leafcnt-f[1]+1<<" "<<g[1]<<endl;
return 0;
}
给一个n个元素的数组。问如果把这个数组当成k(k=1,2,3...n-1)叉堆(小顶堆),分别有多少个元素不合法。不合法是指节点小于自己的父节点。
首先对于k叉堆,每个元素孩子在数组中的下标范围是可以用O(1)计算出来的。我们可以将这n个数从小到大排序,记录下每个元素原来的位置。从小到大将元素的位置加入到树状数组里(其实是先查询),并查询树状数组,自己孩子的那个区间内有多少比自己小的。注意一个细节,先查询完同样大小的所有元素,再更新树状数组。详见代码。
值得一提的是复杂度。因为2叉树大致有n/2个节点有孩子,3叉树大致有n/3,4叉n/4...调和级数的和趋近于ln(n),而树状数组的操作复杂度是log(n)。因此,总复杂度是nlognlogn。。。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n;
int a[maxn];
int rank[maxn];
bool cmp(int x,int y){
return a[x]<a[y];
}
inline int Lmostson(int id,int k){
return id*k-k+2;
}
inline int Rmostson(int id,int k){
return id*k+1;
}
inline int lowbit(int x){
return x&(-x);
}
int c[maxn];
void update(int pos){
while(pos<=n){
c[pos]++;
pos+=lowbit(pos);
}
}
int query(int pos){
int re=0;
while(pos){
re+=c[pos];
pos-=lowbit(pos);
}
return re;
}
int ans[maxn];
int main(){
cin>>n;
a[0]=-1e9-1;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<=n;i++)rank[i]=i;
sort(rank,rank+n+1,cmp);
for(int rnk=1;rnk<=n;rnk++){ //枚举排第rnk位的数
int pos=rank[rnk];
for(int k=1;k<n;k++){ //k叉树
int lson=Lmostson(pos,k);
if(lson>n)break; //没有孩子了,跳出
int rson=Rmostson(pos,k);
if(rson>n)rson=n;
//查询孩子中有多少个小于自己的
int tmp=query(rson)-query(lson-1);
ans[k]+=tmp;
}
//只有当下一个数不同才去更新
if(a[rank[rnk]]!=a[rank[rnk+1]]){
int cur=rnk;
while(1){
update(rank[cur]);
cur--;
if(a[rank[cur]]!=a[rank[cur+1]])break;
}
}
}
for(int i=1;i<n;i++){
printf("%d ",ans[i]);
}
return 0;
}
本文解析了CodeForces平台上的六道算法题,包括字符串处理、贪心算法、图论等,提供了详细的解题思路及代码实现。

被折叠的 条评论
为什么被折叠?



