color

题意

\(\;\)

给定\(p_1,p_2\),要求\(p_1\)的倍数格子填红色,\(p_2\)的倍数格子填蓝色,既是\(p_1\)又是\(p_2\)倍数的格子颜色任选。求是否存在一种填法,满足忽略掉无色格子后不存在个连续\(k\)相同颜色的格子

\(\;\)

比较水的一道题。

用\(gcd(p_1,p_2)\)和贪心乱搞一通,用裴蜀定理证明,没了。

但是千万千万记得要特判\(k=1\)

时间复杂度:\(O(T\;log\;p)\)

code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
LL a, b, k, T;
LL gcd(LL a,LL b)
{
if(b == 0) return a;
return gcd(b , a % b);
}
int main()
{
cin>>T;
while(T--)
{
scanf("%lld%lld%lld",&a,&b,&k);
if(k == 1)
{
puts("No");
continue;
}
if(a > b)swap(a,b);
LL g = gcd(a,b);
LL t = ((b - g) % a == 0) ? 0 : 1;
if((b - g) / a + t < k)puts("Yes");
else puts("No");
}
return 0;
}

\(\;\)

\(\;\)

sequence

\(\;\)

题意

\(\;\)

给一个长度为\(n\)的序列\(A_1,A_2,\cdots,A_n.\;\)定义\(f(l,r)\)为[l,r]中不同的数字个数.求

\(\sum_{l=1}^n \sum_{r=l}^n f(l,r)^2\)

\(\;\)

暴力

\(\;\)

直接枚举\(l,r\),然后在\(r\)不断加\(1\)的同时,更新此时区间中数字种类个数

时间复杂度:\(O(n^2)\)

期望得分:\(50pts\)

\(\;\)

\(\;\)

正解

\(\;\)

直接求平方似乎不太好操作

\(\because f(l,r)^2=f(l,r)(f(l,r)-1)+f(l,r)\)

不妨设\(F(n)=\sum_{i=1}^n f(i,n)\;,\;g(n)=\sum_{i=1}^n f(i,n)(f(i,n)-1)\)

然后我们只需分别求\(\sum_{i=1}^n F(n),g(n)\)即可

关键是怎么求?

\(\;\)

\(\;\)

现在给出一个思路:求\(F(n)-F(n-1)\)与\(g(n)-g(n-1)\)

而\(F(n)\)中的每个区间只比\(F(n-1)\)中的区间多了\(a_n\)

所以我们预处理出\(last_n=j\),\(j<n\)且\(a_j=a_n\)(\(j\)是满足这个条件中最靠后的)

因此只有\([last_n+1,n]\)为\(l\)端点的区间才会多出\(a_r\)这个新的数字,产生\(1\)的贡献,总共多产生了\(n-last_n\)的贡献

\(\therefore F(n)-F(n-1)=n-last_n\)

而这个玩意相当于把\([last_n+1,n]\)这段区间执行\(+1\)的操作

\(\;\)

而求\(g(n)-g(n-1)\)与\(F\)同理。

\([last_n+1,n]\)为\(l\)端点的区间,多产生\(1\)的贡献。

因此:这些区间的\(f(l,r)(f(l,r)-1)=>f(l,r)(f(l,r)+1)\)

\(\because f(l,r)(f(l,r)+1)-f(l,r)(f(l,r)-1)=2\times f(l,r)\)

所以总共会增长:\(2\times \sum_{i=last_n+1}^n f(i,r)\)

而:\(\sum_{i=last_n+1}^n f(i,r)\)实际是一个区间求和的操作

\(\;\)

区间执行\(+1\),区间求和你想到了什么?

没错,就是线段树。

因此在枚举\(r\)(右端点)的过程中用线段树维护区间修改与和。

注意在修改与求和的顺序。

时间复杂度:\(O(n\;log\;n)\)

期望得分:\(100pts\)

code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> using namespace std; const int N = 1000010, mod = 1000000007;
#define LL long long
#define F(i,a,b) for(int i=a;i<=b;i++)
#define ls(x) x<<1
#define rs(x) x<<1|1
int n, a[N], b[N], ap[N], last[N];
LL tree[N << 2], tag[N << 2], f[N], g[N], res1, res2; inline void push_up(int root)
{
tree[root] = (tree[ls(root)] + tree[rs(root)]) % mod;
}
void build (int root, int l, int r)
{
if(l==r)
{
return;
}
int mid = (l + r) >> 1;
build(ls(root), l, mid);
build(rs(root), mid+1, r);
push_up(root);
}
inline void change(int root, int l, int r, LL k)
{
tag[root] = (tag[root] + k) % mod;
tree[root] = (tree[root] + (r-l+1) * k % mod) % mod;
}
void push_down(int root, int l, int r)
{
if(tag[root])
{
int mid = (l + r) >> 1;
change(ls(root), l, mid, tag[root]);
change(rs(root), mid+1, r, tag[root]);
}
tag[root] = 0;
}
void Update(int root, int L, int R, int l, int r, LL k)
{
if(l<=L&&R<=r)
{
change(root,L,R,k);
return;
}
push_down(root,L,R);
int mid = (L + R) >> 1;
if(l <= mid) Update(ls(root), L, mid, l, r, k);
if(r > mid) Update(rs(root), mid+1, R, l, r, k);
push_up(root);
}
LL Query(int root, int L, int R, int l, int r)
{
LL res = 0;
if(l<=L&&R<=r)
{
return tree[root];
}
push_down(root,L,R);
int mid = (L + R) >> 1;
if(l <= mid) res = (res + Query(ls(root), L, mid, l, r)) % mod;
if(r > mid) res = (res + Query(rs(root), mid+1, R, l, r)) % mod;
return res;
}
int main()
{
scanf("%d",&n);
F(i,1,n)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
int m = unique(b+1,b+n+1) - b - 1;
F(i,1,n)
{
a[i] = lower_bound(b+1,b+m+1,a[i]) - b;
}
F(i,1,n)
{
last[i]=ap[a[i]];
ap[a[i]]=i;
}
build(1,1,n);
F(r,1,n)
{
f[r] = (f[r-1] + r - last[r]) % mod;
res1 = (res1 + f[r]) % mod;
g[r] = (g[r-1] + 2 * Query(1,1,n,last[r]+1,r)) % mod;
res2 = (res2 + g[r]) % mod;
Update(1,1,n,last[r]+1,r,1);
}
printf("%lld",(res1 + res2) % mod);
return 0;
}

\(\;\)

\(\;\)

match

\(\;\)

题意

小 A 和小 B 正在玩一个游戏:有一棵包含 \(n\) 个点的有根树(点从 \(1-n\) 编号),它的根是\(1\) 号点,初始时两人各拥有 \(m\) 个点。游戏的每个回合两人都需要选出一个自己拥有且之前未被选过的点,若对手的点在自己的点的子树内,则该回合自己获胜;若自己的点在对方的点的子树内,该回合自己失败;其他情况视为平局。游戏共进行$ m$ 回合。

作为旁观者的你只想知道,在他们随机选点的情况下,第一次非平局回合出现时的回合数的期望值。

为了计算这个期望,你决定对于\(k=0,1,2,\cdots,m\),计算出非平局回合数为\(k\)的情况数。两种情况不同当且仅当存在一个小 A 拥有的点 \(x\),小 B 在\(x\) 被小 A 选择的那个回合所选择的点不同。

由于情况总数可能很大,你只需要输出答案对\(998244353\)取模后的结果

\(\;\)

\(\;\)

暴力

\(\;\)

枚举所有的可能性,对每种情况处理一下统计一下非平局的个数。

时间复杂度:\(O(m!)\)

期望得分:\(20pts\)

\(\;\)

\(\;\)

正解

\(\;\)

\(\;\)

考虑树上DP

\(\;\)

设\(f_{u,i}\)表示以\(u\)为根的子树中,有\(i\)对互为祖先与后代的关系的方案数。

状态转移?其实与各种树上DP的套路类似,考虑\(u\)与它的若干个子树\(v\)的关系

根据乘法原理,有:\(f_{u,j+k}=f_{u,j}\times f_{v,k}\)

但注意:这里的转移不能直接拿\(f\)数组进行,而应先用一个\(tmp\)数组按上面的方程进行转移,再将其赋给\(f\)数组。

原因是我们要保证转移方程中的\(f_{u,j}\)一定是\(v\)这个子树之前的方案数,并没算\(v\)这棵子树的贡献。而若直接用\(f\)数组进行转移,可能导致这里\(f_{u,j}\)是加上了\(v\)这棵子树的结果。其实与01背包的倒序循环类似

\(\;\)

算u的贡献

\(\;\)

因为\(u\)能与它的子树内所有颜色不同的节点组成一对。所以设\(cnt_{u,0/1}\)表示以\(u\)为根的0/1颜色的个数,设\(color_u\)表示\(u\)的颜色。

则与\(u\)不同颜色的节点有\(cnt_{u,color_u \; xor \; 1}\)个。

因此我们可以得到转移方程:

\(f_{u,i}=f_{u,i-1}\times (cnt_{u,color_u \; xor \; 1} - (i-1))\)

\(\;\)

统计答案

\(\;\)

设\(Ans_i\)表示整棵树中有\(i\)对的方案数。则\(Ans_i=f_{1,i}\times (m-i)!\)。等价于选出那\(i\)对后,剩下的随便组合。

但这样并不正确,剩下的点对也有可能组成祖先与后代的关系。

于是我们发现,这其实是一个类似容斥原理的东西。

对于每个有\(i\)对的方案,在统计的时候,由于剩下的点也有可能组成点对,所以其实可能有\(i+1,i+2,\cdots,m\)个点对。

所以我们要将它们减去。

而对于\(i+1\)个点对的每一种方案,都会被算\(C_{i+1}^i\)次,相当于从这些中挑出\(i\)对。

如此类比可得:对于任意的\(j(j>i)\)要减去\(C_j^i \times Ans_j\) 次。

于是通过这样的操作,即可保证不会算重。

时间复杂度

\(\;\)

乍一看是\(O(n^3)\)。但细细观察即可发现,我们在进行树上DP时,相当于是合并两颗子树中的点,只会在它们的LCA处作一次贡献。

所以是\(O(n^2)\)

期望得分:\(100pts\)

\(\;\)

code

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include<algorithm>
using namespace std;
const int N = 5010, mod = 998244353;
int n, m, f[N][N], g[N], siz[N], cnt[N][2], fac[N], color[N], tmp[N];
int Invfac[N];
char str[N];
vector<int> G[N];
void Dfs(int u,int fa)
{
f[u][0] = 1;
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i];
if(v == fa) continue;
Dfs(v,u);
for(int j=0;j<=siz[u]+siz[v];j++)tmp[j] = 0;
for(int j=0;j<=siz[u];j++)
{
for(int k=0;k<=siz[v];k++)
{
tmp[j + k] = (tmp[j + k] + 1LL * f[u][j] * f[v][k] % mod) % mod;
}
}
for(int j=0;j<=siz[u]+siz[v];j++)f[u][j] = tmp[j];
siz[u] += siz[v];
cnt[u][0] += cnt[v][0]; cnt[u][1] += cnt[v][1];
}
siz[u] ++;
cnt[u][color[u]] ++;
for(int j=siz[u];j;j--)
{
f[u][j] = (f[u][j] + 1LL * f[u][j - 1] * (cnt[u][color[u] ^ 1] - j + 1) % mod) % mod;
}
}
int ksm(int a,int b)
{
int res = 1;
while(b)
{
if(b & 1) res = 1LL * res * a % mod;
a = 1LL * a * a % mod;
b >>= 1;
}
return res;
}
int C(int n,int m)
{
return 1LL * fac[n] * Invfac[n - m] % mod * Invfac[m] % mod;
}
int main()
{
cin >> n >> str + 1;
m = n / 2;
for(int i=1;i<=n;i++)
{
color[i] = (str[i] == '0') ? 0 : 1;
}
for(int i=1;i<n;i++)
{
int u, v;
cin >> u >> v;
G[u].push_back(v); G[v].push_back(u);
}
Dfs(1,0);
fac[0] = 1;
for(int i=1;i<=n;i++)
{
fac[i] = 1LL * fac[i - 1] * i % mod;
}
Invfac[0] = 1;
for(int i=1;i<=n;i++)
{
Invfac[i] = 1LL * Invfac[i - 1] * ksm(i,mod - 2) % mod;
}
for(int i=0;i<=m;i++)
{
g[i] = 1LL * fac[m - i] * f[1][i] % mod;
}
for(int i=m;i>=0;i--)
{
for(int j=i+1;j<=m;j++)
{
g[i] = (g[i] - 1LL * C(j,i) * g[j] % mod + mod) % mod;
}
}
for(int i=0;i<=m;i++)printf("%d\n",g[i]);
return 0;
}

NOI Online #2 赛后题解的更多相关文章

  1. 牛客NOIP暑期七天营-TG1 赛后题解

    目录 牛客NOIP暑期七天营-提高组1 A-最短路 题目描述 link 题解 代码 B-最小生成链 题目描述 link 题解 代码 C-最小字典最短路 题目描述 link 题解 Update 牛客NO ...

  2. NOI 2021 部分题目题解

    最近几天复盘了一下NOI 2021,愈发发觉自己的愚蠢,可惜D2T3仍是不会,于是只写前面的题解 Day1 T1 可以发现,每次相当于将 \(x\to y\) 染上一种全新颜色,然后一条边是重边当且仅 ...

  3. NOI 2011 兔农 题解

    事先声明,本博客代码主要模仿accepoc,且仅针对一般如本博主一样的蒟蒻. 这道题不得不说数据良心,给了75分的水分,但剩下25分真心很难得到,因此我们就来讲一讲这剩下的25分. 首先,有数据可知他 ...

  4. 牛客NOIP暑期七天营-TG3 赛后题解

    目录 牛客NOIP暑期七天营-提高组3 A-破碎的矩阵 题目描述 link 题解 代码 B-点与面 题目描述 link 题解 代码 C-信息传递 题目描述 link 题解 牛客NOIP暑期七天营-提高 ...

  5. NOI Online 提高组 题解

    来补坑了-- 个人认为三道题难度差不多-- 还有要说一嘴,为啥我在其他网站代码都好好的,复制到 cnblogs 上 Tab 就成 8 空格了?不过也懒得改了. T1 序列 首先,遇到这种加一减一还带附 ...

  6. JZOJ 5409 Fantasy & NOI 2010 超级钢琴 题解

    其实早在 2020-12-26 的比赛我们就做过 5409. Fantasy 这可是紫题啊 题目大意 给你一个序列,求长度在 \([L,R]\) 区间内的 \(k\) 个连续子序列的最大和 题解 如此 ...

  7. NOI 题库 8471 题解

    8471   切割回文 描述 阿福最近对回文串产生了非常浓厚的兴趣. 如果一个字符串从左往右看和从右往左看完全相同的话,那么就认为这个串是一个回文串.例如,“abcaacba”是一个回文串,“abca ...

  8. NOI 题库 9272 题解

    9272   偶数个数字3 描述 在所有的N位数中,有多少个数中有偶数个数字3? 输入 一行给出数字N,N<=1000 输出 如题 样例输入 2 样例输出 73 Solution : 令f ( ...

  9. 【CYH-02】noip2018数论模拟赛:赛后题解

    1.小奔的矩阵 2.大奔的方案 3.小奔与不等四边形 4.小奔的方案 当然本次比赛肯定难度不会仅限于此啦!后续还会--

随机推荐

  1. cli命令速查

    在文件的指定行(n)插入指定内容: sed -i "niecho "haha"" a 执行后,在a文件的第n行插入echo "haha" 多 ...

  2. Dockerfile的简单人门编写之关于yum的问题

    首先我们编写一个简单的Dockerfile的例子.不过再此之前大家得去把编写dockerfile的指令了解一下. 编写以 centos镜像为基础镜像,构建 http 服务,Dockerfile 要求删 ...

  3. springmvc配置数据源方式

    1 阿里巴巴的druid数据源 <!-- 配置数据源 使用的是Druid数据源 -->-<bean destroy-method="close" init-met ...

  4. Django新手十个开发指导

    下面是关于Django新手开发中的一些建议,大家可以参考一下~~ 1,不要将项目名称包含在引用代码里 比如你创建了一个名为"project"的项目,包含一个名为"app& ...

  5. 第三方库PyYAML

    建议参考PyYAML Documentation来源:http://pyyaml.org/wiki/PyYAMLDocumentation:http://blog.csdn.net/conquer07 ...

  6. Vue 结合 echarts 原生 html5 实现拖拽排版报表系统

    前言 不知道各位 coder 有没有碰到过许多重复的业务需求,比如排版相类似的报表,只不过是顺序稍微换了一下,就是一个新的页面,虽然基于模板思想来写的话也能减少不少代码,但是相对的不那么方便,笔者最近 ...

  7. 接口自动化测试平台-接入持续集成jenkins

    开篇提到,自动化测试最终期望还是能接入持续集成系统jenkins,下面记录下Go接口自动化测试平台是如何设计接入jenkins的. 回到Go接口自动化测试平台,在web系统中触发测试任务执行的入口为: ...

  8. Vue学习—— Vuex学习笔记

    组件是Vue最强大的功能之一,而组件实例的作用域是相互独立的,意味着不同组件之间的数据是无法相互使用.组件间如何传递数据就显得至关重要,这篇文章主要是介绍Vuex.尽量以通俗易懂的实例讲述这其中的差别 ...

  9. 网课应该这么刷(油猴Tampermonkey脚本自动刷课)

    懒人福利 首先有些人不想学怎么用脚本,满足你们,压缩包解压之后直接登录即可.戳我下载 脚本已经集成好了,登录即可刷课.章节测试还会自动答题呦,正确率高达97%呦. 油猴及脚本安装 油猴的脚本不知可以刷 ...

  10. The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 K题 center

    You are given a point set with nn points on the 2D-plane, your task is to find the smallest number o ...