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. 基于thinkphp3.2.3开发的CMS内容管理系统 - ThinkPHP框架

    基于thinkphp3.2.3开发的CMS内容管理系统 thinkphp版本:3.2.3 功能: --分类栏目管理 --文章管理 --用户管理 --友情链接管理 --系统设置 目前占时这些功能,更多功 ...

  2. Java中集合概念

    集合的由来: 我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行储存,而想要储存多个对象,就不能是一个基本的变量,而应该是一个 ...

  3. tensorflow1.0 队列FIFOQueue管理实现异步读取训练

    import tensorflow as tf #模拟异步子线程 存入样本, 主线程 读取样本 # 1. 定义一个队列,1000 Q = tf.FIFOQueue(1000,tf.float32) # ...

  4. java 多线--静态代理模式

    我们使用 java 多线程时,都需要通过线程代理对象来启动线程,常见的写法: new Thread(target).start(); 这在设计模式中叫静态代理模式,静态代理模式组成; 1.公共接口 2 ...

  5. 关于JavaEE中Spring模块的学习!

    七大模块,如下: 1. Spring Core: Core封装包是框架的最基础部分,提供IOC和依赖注入特性.这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性 ...

  6. Caused by: java.io.IOException: Type mismath in vlaue from map: excepted org.apache.hadoop.io.InaWritable,received SC

    解决办法: 看map和reduce的输入是不是对应,看看map和reduce设置的参数和下面的是否一致

  7. Unity 游戏框架搭建 2019 (三十六~三十八) partial与public

    在上一篇,我们把菜单的顺序从头到尾整理了一遍.在整理菜单顺序的过程中,记录了一个要做的事情. 要做的事情: (完成) 备份:导出文件,并取一个合理的名字. 整理完菜单顺序后,学习新的知识,解决随着示例 ...

  8. java传参问题

    参考链接:https://www.cnblogs.com/linkstar/p/5951141.html public class Example { String testString = publ ...

  9. vector做形参时的三种传参方式

    vector在做形参的时候传参的方式和普通的变量是一样的,要么传值.要么传引用.要么传指针. 现在分别定义三个以vector为形参的函数: (1) fun1(vector <int> v) ...

  10. sql注入 pikachu

    闭合条件的探测 数字型注入 burp抓包 分别测试 id=1 and 1=1和id=1 or 1=1 存在漏洞 字符型注入 ' 报错 探测闭合条件 ' order by 1# 未报错.构成闭合 同上有 ...