Codeforces Round #722 (Div. 2)
B. Sifid and Strange Subsequences
思路:
题目要求子序列两两之间的值全部大于等于MAX,不妨给序列排序。
排序后,对于序列,只需在意相邻是数是否大于等于MAX。
很容易看出,所有非正数都是满足的,现在对多能加入一个正数,选最小的正数看是否比原先答案更优。
代码实现:
#include <iostream>
#include <set>
using namespace std;
const int N=1e5+7;
int t;
int n,a[N];
set <int> sa;
int dfs(int p,int mx){
auto it=sa.upper_bound(p-mx);
int ans=0;
if(it==sa.begin()){
return 1;
}else{
it--;
ans=dfs(*it,mx)+1;
}
return ans;
}
int main(){
cin>>t;
while(t--){
cin>>n;
sa.clear();
int ans=0;
for(int i=1;i<=n;i++){
cin>>a[i];
sa.insert(a[i]);
if(a[i]<=0) ans++;
}
for(auto i=sa.begin();i!=sa.end();i++){
if(*i>0){
ans=max(ans,dfs(*i,*i));
break;
}
}
cout<<ans<<endl;
}
}
C. Parsa’s Humongous Tree
思路:
结论:
可以得出,结点的值只可能取 l i , r i l_i,r_i li,ri两种(证明不会,打草稿猜测出来的)。
树形dp:
f l [ u ] 为 u fl[u]为u fl[u]为u节点的值为 l u l_u lu的答案。
f r [ u ] 为 u fr[u]为u fr[u]为u节点的值为 r u 的 答 案 r_u的答案 ru的答案
状态转移方程为:
f l [ u ] + = m a x ( f l [ v ] + a b s ( l [ u ] − l [ v ] ) , f r [ v ] + a b s ( l [ u ] − r [ v ] ) ) fl[u]+=max(fl[v]+abs(l[u]-l[v]),fr[v]+abs(l[u]-r[v])) fl[u]+=max(fl[v]+abs(l[u]−l[v]),fr[v]+abs(l[u]−r[v]))
f r [ u ] + = m a x ( f l [ v ] + a b s ( r [ u ] − l [ v ] ) , f r [ v ] + a b s ( r [ u ] − r [ v ] ) ) fr[u]+=max(fl[v]+abs(r[u]-l[v]),fr[v]+abs(r[u]-r[v])) fr[u]+=max(fl[v]+abs(r[u]−l[v]),fr[v]+abs(r[u]−r[v]))
代码实现:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e5+7;
struct node{
ll l,r;
}a[N];
int t,n;
ll fl[N],fr[N];
vector <int> ho[N];
void dfs(int p,int fa){
for(int i=0;i<ho[p].size();i++){
int v=ho[p][i];
if(v==fa) continue;
dfs(v,p);
fl[p]+=max(fr[v]+abs(a[p].l-a[v].r),fl[v]+abs(a[p].l-a[v].l));
fr[p]+=max(fr[v]+abs(a[p].r-a[v].r),fl[v]+abs(a[p].r-a[v].l));
}
}
void init(){
for(int i=0;i<=n+1;i++){
ho[i].clear();
fl[i]=fr[i]=0;
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
init();
for(int i=1;i<=n;i++){
scanf("%lld %lld",&a[i].l,&a[i].r);
}
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d %d",&u,&v);
ho[u].push_back(v);
ho[v].push_back(u);
}
dfs(1,-1);
printf("%lld\n",max(fl[1],fr[1]));
}
}
D. Kavi on Pairing Duty
思路:
符合题意的可分为两种:
-
线段不覆盖,且所有线段相等
-
线段存在覆盖
存在覆盖的线段可被1,2…i-1覆盖,即可得
f [ i ] = ∑ j = 1 j = i − 1 f [ j ] f[i]=\sum_{j=1}^{j=i-1}f[j] f[i]=∑j=1j=i−1f[j]
不被覆盖的为 i i i的因子数。
代码实现:
#include <iostream>
using namespace std;
typedef long long ll;
const int N=1e6+7;
const ll mod=998244353;
int n;
ll f[N],count[N];
int main(){
scanf("%d",&n);
f[1]=1,f[2]=3;
ll sum=4;
for(int i=1;i<=n;i++ )
for(int j=i;j<=n;j+=i)
count[j]++;
for(int i=3;i<=n;i++){
f[i]=(sum+count[i])%mod;
sum=(sum+f[i])%mod;
}
printf("%lld\n",f[n]);
}