Codeforces Round #964
A Splits(思维+数学)
传送门:A
Description
我们定义正整数 \(n\) 的分裂为一个由正整数组成的不上升序列,且序列数字和为 \(n\)
举个栗子:下列这些序列都是 \(8\) 的分裂:\([4,4],[3,3,2],[2,2,1,1,1],[5,2,1]\)
下列这些序列不是 \(8\) 的分裂:\([1,7],[5,4],[11,-3],[1,1,4,1,1]\)
一个分裂的权是序列第一个数出现的次数,举个例子:\([1,1,1,1,1]\) 的权是 \(5\),\([5,5,3,3,3]\) 的权是 \(2\),\([9]\) 的权是 \(1\)
现在给出 \(n\),求 \(n\) 的分裂有多少个不同的权
\(n\leq 10^9\)
Solution
分情况讨论:
- 如果权重等于 \(n\),那么所有都赋 \(1\) 就可以啦,方案数为 \(1\)。
- 否则,最大值超过 \(1\),我们设最大值为 \(2\) 来进行简化(更大的值产生的权的数量一定不会比这个更大,而且全部被包含)。这样我们只要枚举有多少个 \(2\) 就可以啦,其余全部填 \(1\),方案数为 \(\frac{n}{2}\)。
总的方案数为 \(\frac{n}{2}+1\)。
#include<bits/stdc++.h>
using namespace std;
int n;
signed main()
{
scanf("%d",&n);
printf("%d\n",n / 2 + 1);
return 0;
}
B Messages(贪心+模拟)
传送门:B
Description
Vasya 有 \(n\) 封信。第 \(i\) 封信将在 \(t_i\) 秒之后接收。 每封信都开始都值 \(a\) 元,但收到消息后,消息的成本每分钟减少 \(B\) 元(\(B\) 可能变为负数)。Vasya 可以在任意时刻接收到任何消息,也可在任意时刻读取它。读完消息后,Vasya 的银行账户会收到该消息的当前成本。最初,Vasya 的银行账户为 \(0\)。 同时,每分钟 Vasya 的银行账户会收到 \(C\times k\) 元,\(k\) 是收到了但未读信的数量。 Vasya 非常贪婪(又一个葛朗台),正因为如此,他想让所有的信息在 \(T\) 分钟后被阅读,使其利益最大化。
Solution
一个很容易想到的贪心思路是,如果 \(C > B\),那么我们在 \(T\) 时刻读取所有信件,否则我们选择在收到这封信的同时直接读取信件。剩余的按照题意模拟即可。
#include<bits/stdc++.h>
using namespace std;
int n,a,b,c,T,res,awa;
int t[1010];
signed main()
{
scanf("%d%d%d%d%d",&n,&a,&b,&c,&T);
for(int i = 1;i <= n;i++)
{
scanf("%d",&t[i]);
res += T - t[i];
}
awa = n * a;
if(b < c) awa += res * (c - b);
printf("%d\n",awa);
return 0;
}
C Alternating Sum(思维+数学)
传送门:C
Description
给你两个整数 \(a\) 和 \(b\) 。再给你一个序列 \(s_0, s_1, \cdots, s_n\),其中 \(s_i\) 要么为 \(1\) ,要么为 \(-1\) 。
已知这个序列以 \(k\) 为周期并且 \(k\) 整除 \(n + 1\) ,换句话说,对于所有满足 \(k \leq i \leq n\) 的 \(i\) 都有 \(s_i = s_{i - k}\) 。
求出下式在模 \(10^9 + 9\) 意义下的值:
\(\sum_{i = 0}^{n} s_i a^{n - i}b^i\)
Solution
我们发现,这个序列显然是由周期为 \(k\) 的子序列进行循环的,对应项 \(s_i\) 相等,且后面的值对应项形成一个公差为 \((\frac{b}{a})^k\) 的等比数列,那么直接使用等比数列求和公式就可以啦,需要处理逆元,正向扫一遍即可。时间复杂度 \(O(klogn)\)。(注意:需要特判公差为 \(1\) 的情况,等比数列公式会炸,直接都相等即可)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1000000009;
const int N = 100000 + 10;
int n,a,b,k,ans;
int ksm(int x,int y)
{
int res = 1;
for(;y;y >>= 1,x = x * x % mod) if(y bitand 1) res = res * x % mod;
return res;
}
char sig[N];
int s[N];
signed main()
{
scanf("%lld%lld%lld%lld",&n,&a,&b,&k);
scanf("%s",sig);
int ox = (n + 1) / k;
for(int i = 0;i < k;i++)
s[i] = (sig[i] == '+') ? 1 : (mod - 1);
int q = ksm(b,k) * ksm(ksm(a,k),mod - 2) % mod;
for(int i = 0;i < k;i++)
{
int cur = ksm(a,n-i) * ksm(b,i) % mod;
int nox = (ksm(b,n + 1) * ksm(ksm(a,n + 1),mod - 2) % mod - 1 + mod) % mod;
int pox = (ksm(b,k) * ksm(ksm(a,k),mod - 2) % mod - 1 + mod) % mod;
pox = ksm(pox,mod - 2);
pox = pox * nox % mod * cur % mod;
if(q == 1) ans = (ans + s[i] * cur % mod * ox % mod) % mod;
else ans = (ans + s[i] * pox % mod) % mod;
}
printf("%lld\n",ans);
return 0;
}
D Destruction of a Tree(思维+树上 DFS)
传送门:D
Description
给你一棵树,如果树上的节点有偶数条边与它相连,则这个节点是可删除的,删除这个节点后所有与之相连的边也将删除。判断一棵树是否可以依次删除所有节点。
输入: 第一行:一个整数 \(n\)
第二行:\(n\) 个整数 \(P_i\),表示编号为 \(i\) 的点与编号为 \(P_i\) 的点相连,保证是一棵树
输出: 可以删除输出 YES,并输出依次删除的点的编号;不可以则输出 NO
Solution
水紫。考虑直接暴力删边。先自顶向下搜,遇到度数为偶数的就删除与之相连的所有边,并加入答案序列。这时剩下的点再自顶向下搜一遍,如果度数为偶数那么就删边更新答案序列,如果是奇数那么无论如何也删不掉(因为他上面和下面的偶数已经被删完了),答案不存在。最后输出答案序列即可。由于每条边只访问了一次,所以整体时间复杂度上限为 \(O(n+m)\)。
#include<bits/stdc++.h>
using namespace std;
const int N = 200000 + 10;
int n,root,len,tot,flag;
int cnt[N],seq[N],vis[N],head[N],ver[2*N],Next[2*N];
void add(int x,int y)
{
ver[++tot] = y,Next[tot] = head[x],head[x] = tot;
}
void cancel(int x)
{
seq[++len] = x;
vis[x] = 1;
for(int i = head[x];i;i = Next[i])
{
int v = ver[i];
cnt[v]--;
}
}
void dfs(int u,int fa)
{
for(int i = head[u];i;i = Next[i])
{
int v = ver[i];
if(v == fa) continue;
dfs(v,u);
}
if(cnt[u] % 2 == 0) cancel(u);
}
void gfs(int u,int fa)
{
if(not vis[u] and cnt[u] % 2 == 0) cancel(u);
else if(not vis[u] and cnt[u] & 1) flag = 1;
for(int i = head[u];i;i = Next[i])
{
int v = ver[i];
if(v == fa) continue;
gfs(v,u);
}
}
signed main()
{
tot = 1;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
int sop;
scanf("%d",&sop);
if(not sop) root = i;
else
{
add(i,sop);
add(sop,i);
cnt[sop]++;
cnt[i]++;
}
}
dfs(root,0);
gfs(root,0);
if(flag)
{
printf("NO\n");
return 0;
}
printf("YES\n");
for(int i = 1;i <= len;i++) printf("%d\n",seq[i]);
return 0;
}
E Cutting Rectangle
传送门:E
还没错,本雪就是菜 qaq

浙公网安备 33010602011771号