链接
https://codeforces.com/contest/1491
A. K-th Largest Value
(rating:800)
题意:
给一个仅含0,1的序列 a, 进行以下两个操作:
- 把ai 如果是0换成1,如果是1换成0
- 输出第k大元素
思路:
记录下当前有几个0几个1即可。
B. Minimal Cost
(rating:1200)
题意:
初始位置在(1,0) ,要到(n,106+1 ).
每行有且仅有一个障碍物 。 移动障碍物时,横着移动一格需要耗费体力v, 竖着移动一个需要体力u 。 问能到达终点 最少体力花费。(障碍物只能在第1列至第106 列之间)
思路:
相邻两行的障碍物,如果列数相差2以上,无需移动,直接穿过去即可,耗费体力 = 0。
相邻两行的障碍物,如果列数相差1,耗费体力 = min(u,v)。
相邻两行的障碍物如果列数相同 , 耗费体力 = min(u+v,v+v)。
对所有相邻行判断取最小值。
C. Pekora and Trampoline(贪心)
(rating:1700)
题意:
有从左到右n个蹦床 , 每个蹦床的弹性是Si 。 当落在第i个蹦床上时 , 会被弹到第i+Si个蹦床上 , 直到弹出这n个蹦床 。
每从一个蹦床上弹起后,该蹦床的弹性会衰减 1 , 对于Si = 1,则不再衰减 。
问最少弹多少个回合能使所有蹦床弹性都为1 .
思路:
不难发现 , 越靠左的非1蹦床早晚都得跳掉 , 而且弹起高度只取决于当前蹦床 。 那么贪心即可 。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn = 5050;
ll a[maxn];
ll n;
ll b[maxn];
int main(){
int t;
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
ll ans = 0;
for(int i=1;i<=n;i++){
if(a[i]!=1){
ans += max((ll)0,(a[i]-b[i]-1));
}
for(int j=n;j>i+1;j--){
if(j-i<=a[i])
b[j]++;
}
ll z = b[i] - a[i] + 1;
b[i+1] += max(z,(ll)0);
}
cout<<ans<<endl;
for(int i=1;i<=n+5;i++)
b[i] = 0;
}
}
D. Zookeeper and The Infinite Zoo(数学)
(rating:1800)
题意:
若u&v = v , 就在u —> u+v 上增加一条边 。
给两个数a,b . 问a能否到b 。
思路:
u&v==v
那么u是 0 的地方v不能是1 。
那么u+v 中1的位置必然不小于 u中1的位置 。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
bool check(int u,int v){
int a=0,b=0;
for(int i=0;i<=32;i++){
if(u>>i&1) a++;
if(v>>i&1) b++;
if(b>a)
return 0;
}
return 1;
}
int main(){
int t;
cin>>t;
while(t--){
int u,v;
scanf("%d %d",&u,&v);
if(u>v)
printf("NO\n");
else if(u==v)
printf("YES\n");
else{
if(check(u,v)==1)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
E. Fib-tree(树论)
(rating:2400)
题意:
判断一棵树是否是fib(斐波那契)树。
fib树定义如下:
1.fib树的节点个数是斐波那契数 。
2.节点数大于1的fib树可以分成两棵fib树 。 (递归定义)
思路:
挺难但很好的一道题 , 从这道题学会了很多。。
主要就是两个问题,
一个是链式前向星的删边 cut[i] = cut[i^1] = 1,
一个是子树节点的存储 。
方法就是每次找到满足分割条件的节点u时,把节点u与节点fa[u]看成两棵新树的根 , 继续找size满足Fibonacci的节点 。 由于每次dfs都是新的树根 , 因此每次dfs都必须对size做重新处理。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn = 5e5+20;
struct E{
ll to;
ll nxt;
}e[maxn<<1];
ll head[maxn],tot=-1;
ll cut[maxn];
void add_edge(ll u,ll v){
e[++tot].to = v;
e[tot].nxt = head[u];
head[u] = tot;
}
ll sz[maxn];
ll fib[maxn<<2],fac[maxn];
void pre(){
fib[1] = 1,fib[2] = 1,fac[1] = 1;
for(ll i=3;i<=40;i++){
fib[i] = fib[i-1]+fib[i-2];
if(fib[i]>=200005)
break;
fac[fib[i]] = 1;
//cout<<fib[i]<<endl;
}
}
ll now = 0;
ll loc = 0;ll fa[maxn];
void dfs(ll u,ll f,ll siz,ll num){
//cout<<u<<endl;
fa[u] = f;
sz[u] = 1;
for(ll i=head[u];i>=0;i=e[i].nxt){
ll v = e[i].to;
if(v==f) continue;
if(cut[i]==1) continue;
//cout<<v<<endl;
dfs(v,u,siz,i);
sz[u] += sz[v];
}
if(fac[sz[u]]==1&&fac[siz-sz[u]]==1){
//cout<<"ok"<<endl;
now = u;
//cout<<size[u]<<endl;
loc = num;
}
}
void solve(ll root,ll siz){
//cout<<now<<endl;
if(siz==1)
return;
now = 0;
dfs(root,0,siz,-1);
if(now==0){
cout<<"NO"<<endl;
exit(0);
}
cut[loc] = cut[loc^1] = 1;
ll fa_now = fa[now] , fa_size = siz - sz[now];
solve(now,sz[now]);
solve(fa_now,fa_size);
}
int main(){
memset(head,-1,sizeof(head));
pre();
ll n;
cin>>n;
for(int i=1;i<n;i++){
ll x,y;
scanf("%lld %lld",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
if(fac[n]==0){
cout<<"NO"<<endl;
return 0;
}
solve(1,n);
cout<<"YES"<<endl;
return 0;
}