A.Eshag Loves Big Arrays(贪心)
统计最小的数出现次数为cnt 则答案为n-cnt
因为每次都可以一个最小的数加一个大的数来消掉大的数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
const int N=1e5+10;
void solve()
{
map<int,int>m;
int n;
cin>>n;
int mi=105;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
m[x]++;
mi=min(mi,x);
}
cout<<n-m[mi]<<endl;
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
B.Sifid and Strange Subsequences(贪心)
首先把负数和0都拿。然后计算这些数里面距离最近的值C(排序以后On可以算出来)。如果有正数小于等于C,那么答案加一。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
const int N=1e5+10;
int a[N];
void solve()
{
int n;
cin>>n;
int ans=0,c1=0,c0=0;
vector<pii>v;
for(int i=0; i<n; i++)
{
int x;
cin>>x;
a[i]=x;
if(x<=0)v.push_back({x,i}),ans++;
}
int mi=2e9;
sort(v.begin(),v.end());
for(int i=1; i<v.size(); i++)
{
mi=min(mi,abs(v[i].first-v[i-1].first));
}
for(int i=0; i<n; i++)
{
if(a[i]>0&&a[i]<=mi)
{
ans++;
break;
}
}
if(v.empty())ans=1;
printf("%d\n",ans);
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C.Parsa’s Humongous Tree(树形dp)
树形dp模板题,首先要猜到每个点一定是取l或者r。因为如果枚举l到r的话复杂度就爆炸了嘛!然后就有dp方程
f
[
i
]
[
2
]
f[i][2]
f[i][2]表示 i 节点取 l或者r的最大值。然后枚举一下儿子是取什么转移即可
f
[
u
]
[
0
]
+
=
m
a
x
(
f
[
i
]
[
0
]
+
a
b
s
(
l
[
u
]
−
l
[
i
]
)
,
f
[
i
]
[
1
]
+
a
b
s
(
l
[
u
]
−
r
[
i
]
)
)
;
f[u][0]+=max(f[i][0]+abs(l[u]-l[i]),f[i][1]+abs(l[u]-r[i]));
f[u][0]+=max(f[i][0]+abs(l[u]−l[i]),f[i][1]+abs(l[u]−r[i]));
f
[
u
]
[
1
]
+
=
m
a
x
(
f
[
i
]
[
0
]
+
a
b
s
(
r
[
u
]
−
l
[
i
]
)
,
f
[
i
]
[
1
]
+
a
b
s
(
r
[
u
]
−
r
[
i
]
)
)
;
f[u][1]+=max(f[i][0]+abs(r[u]-l[i]),f[i][1]+abs(r[u]-r[i]));
f[u][1]+=max(f[i][0]+abs(r[u]−l[i]),f[i][1]+abs(r[u]−r[i]));
最终答案为
m
a
x
(
f
[
1
]
[
0
]
,
f
[
1
]
[
1
]
)
max(f[1][0],f[1][1])
max(f[1][0],f[1][1])
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
const int N=1e5+10;
ll f[N][2],l[N],r[N];
vector<int>g[N];
void dfs(int u,int fa)
{
for(auto i:g[u])
{
if(i==fa)continue;
dfs(i,u);
f[u][0]+=max(f[i][0]+abs(l[u]-l[i]),f[i][1]+abs(l[u]-r[i]));
f[u][1]+=max(f[i][0]+abs(r[u]-l[i]),f[i][1]+abs(r[u]-r[i]));
}
}
void solve()
{
int n;
cin>>n;
memset(f,0,sizeof f);
for(int i=1;i<=n;i++)scanf("%lld%lld",&l[i],&r[i]),g[i].clear();
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
printf("%lld\n",max(f[1][0],f[1][1]));
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
D.Kavi on Pairing Duty(递推)
先考虑不是全部长度都一样长的方案数
当前枚举到n。那么连1和2n以后,2~2n-1这段位置就是n-1的答案,连1和2n再连2和2n-1以后,
3~2*n-2这段就是n-2的答案。所以有个取前缀答案的过程。
然后考虑全部长度都一样长的方案数
会发现对于n。全部不交叉长度一样的有一种。ling
对于有交叉,长度一样的个数。画图后发现是n的因子个数-1。求因子个数用线性筛或者埃式筛都可以
具体看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
const int N=1e6+10,mod=998244353;
int prime[N],cnt;
bool st[N];
ll num[N],d[N],f[N];
void ini()
{
num[1]=1;
d[1]=1;
for(int i=2;i<N;i++)
{
if(!st[i])
{
prime[cnt++]=i;
d[i]=1;
num[i]=2;
}
for(int j=0;prime[j]<=N/i;j++)
{
st[i*prime[j]]=1;
if(i%prime[j]==0)
{
d[i*prime[j]]=d[i]+1;
num[i*prime[j]]=num[i]/(d[i]+1)*(d[i]+2);
break;
}
d[i*prime[j]]=1;
num[i*prime[j]]=num[i]*2;
}
}
}
void solve()
{
int n;
scanf("%d",&n);
printf("%lld\n",f[n]%mod);
}
int main()
{
ini();
f[1]=1;
ll sum=1;
for(int i=2;i<N;i++)
{
f[i]=(sum+num[i])%mod;
sum=(sum+f[i])%mod;
}
solve();
return 0;
}