A:Domino on Windowsill
简单模拟。两侧都竖着放,中间交错的地方横着放,这样贪心的方法肯定是最优的,然后判断即可。
B:Binary Removals
思维题。最后的串是一个单调非下降的子序列,我们不妨去枚举这样的01的分界点,这样前面半个串必须为0,后面半个串必须为1,然后再进行修改,这样很容易判断出修改是否有问题。
C:Minimum Grid Path
贪心题。我们可以发现当
i
i
i是奇数的时候,我们可以得到
(
i
+
1
)
/
2
,
i
/
2
(i+1)/2,i/2
(i+1)/2,i/2个两种方向不同的线段,当
i
i
i时偶数的时候,我们可以分别得到
i
/
2
i/2
i/2个两种不同方向的线段。然后我们分别去统计出现在奇数位置和出现在偶数位置的最大值,给他们安排的长度是最长的,剩下的都是1即可。
D:The Number of Pairs
题目大意是给定
c
,
d
,
x
c,d,x
c,d,x,问能够找到多少对
a
,
b
a,b
a,b,使得
c
∗
l
c
m
(
a
,
b
)
−
d
∗
g
c
d
(
a
,
b
)
=
x
c*lcm(a,b)-d*gcd(a,b)=x
c∗lcm(a,b)−d∗gcd(a,b)=x成立。
首先,我们可以改成
a
=
A
g
,
b
=
B
g
(
g
c
d
(
A
,
B
)
=
1
)
a=Ag,b=Bg(gcd(A,B)=1)
a=Ag,b=Bg(gcd(A,B)=1),这样问题就转换成了
g
∗
(
c
A
B
−
d
)
=
x
g*(cAB-d)=x
g∗(cAB−d)=x成立的结果数。很明显
g
g
g必然是
x
x
x的一个因数,这可以在
O
(
x
)
O(\sqrt x)
O(x)的时间内进行枚举,然后我们就可以得到
k
1
=
x
g
+
d
k_1=\frac {x}{g}+d
k1=gx+d,则
c
c
c也必须是
k
1
k_1
k1的一个因子,直接判断即可。这时候我们的
A
B
=
k
2
=
x
+
d
g
g
c
AB=k_2=\frac {x+dg}{gc}
AB=k2=gcx+dg,
A
,
B
A,B
A,B互质的条件可以通过对
k
2
k_2
k2进行质因数分解,他们各自占一部分的质因子,交集为空,并集恰好是
k
2
k_2
k2全部的质因子。假设
k
2
k_2
k2的质因数有
n
n
n个,那么答案应该是
2
n
2^n
2n个。同时我们可以通过预处理的方式,一次性得到从1~MAXN的所有正整数的质因数个数。
#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
const int maxn=2e7+100;
int val[maxn];
void Init()
{
for(int i=2;i<maxn;++i)
if(!val[i])
for(int j=i;j<maxn;j+=i) val[j]++;
}
int main()
{
close;int T;cin>>T;
Init();
while(T--)
{
int c,d,x,ans=0;cin>>c>>d>>x;
for(int i=1;i*i<=x;++i)
{
if(x%i!=0) continue;
int k1=x/i+d;
if(k1%c==0) ans+=1<<val[k1/c];
if(i*i==x) continue;
int k2=i+d;
if(k2%c==0) ans+=1<<val[k2/c];
}
cout<<ans<<endl;
}
}
E:Chaotic Merge
F:Diameter Cuts
题目大意是给定一棵无根树,你可以选择删除一些边,使得删边后得到的所有子树的直径都
≤
k
\le k
≤k,问有多少种删边方案。
考虑到树的直径的树形DP的求解方案。我们都假设一开始以
r
o
o
t
root
root为根结点的子树的最左侧有一棵空树,然后我们不断更新以
r
o
o
t
root
root为端点的最长的树链。在合并的时候,假设
u
u
u是
r
o
o
t
root
root的一个子结点,分为两种情况:①如果以
u
u
u为端点的最长链和以
r
o
o
t
root
root为端点的最长链加起来并加上1后的长度没有
k
k
k长,那么我们可以去计数他俩相连的方案;②看看各自的子树中的最长链是否都没有
k
k
k长,就独立地对答案有一部分的贡献。需要注意的是,我们需要原始的数据进行计数,因此更新的时候需要先开一个临时存储空间。
#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
const int maxn=5e3+100;
const int mod=998244353;
typedef long long ll;
ll dp[maxn][maxn],tmp[maxn],n,k;
vector<int> v[maxn];
int DFS(int root,int fa)
{
int maxheight=0;dp[root][0]=1;
for(int u:v[root]){
if(u==fa) continue;
int child=DFS(u,root);
memset(tmp,0ll,sizeof(tmp));
for(int i=0;i<=maxheight;++i)
for(int j=0;j<=child;++j)
{
if(i+j+1<=k) tmp[max(i,j+1)]=(tmp[max(i,j+1)]+dp[root][i]*dp[u][j]%mod)%mod;
if(i<=k && j<=k) tmp[i]=(tmp[i]+dp[root][i]*dp[u][j]%mod)%mod;
}
maxheight=max(maxheight,child+1);
for(int i=0;i<=maxheight;++i) dp[root][i]=tmp[i];
}
return maxheight;
}
int main()
{
close;cin>>n>>k;
for(int i=1;i<n;++i)
{
int x,y;cin>>x>>y;
v[x].push_back(y);v[y].push_back(x);
}
DFS(1,-1);
ll ans=0;
for(int i=0;i<=k;++i) ans=(ans+dp[1][i])%mod;
cout<<ans;
}