NOIP模拟17.8.15

A 债务
文件名 输入文件 输出文件 时间限制 空间限制
debt.pas/c/cpp debt.in debt.out 1s 128MB
【题目描述】
小 G 有一群好朋友,他们经常互相借钱。假如说有三个好朋友 A,B,C。A
欠 B 20 元,B 欠 C 20 元,总债务规模为 20+20=40 元。小 G 是个追求简约的人,
他觉得这样的债务太繁杂了。他认为,上面的债务可以完全等价为 A 欠 C 20 元,
B 既不欠别人,别人也不欠他。这样总债务规模就压缩到了 20 元。
现在给定 n 个人和 m 条债务关系。小 G 想找到一种新的债务方案,使得每个
人欠钱的总数不变,或被欠钱的总数不变(但是对象可以发生变化),并且使得总
债务规模最小。
【输入格式】
输入文件第一行两个数字 n, m,含义如题目所述。
接下来 m 行,每行三个数字 ai, bi, ci,表示 ai 欠 bi 的钱数为 ci。
注意,数据中关于某两个人 A 和 B 的债务信息可能出现多次,将其累加即可。
如”A 欠 B 20 元”、”A 欠 B 30 元”、”B 欠 A 10 元”,其等价为”A 欠 B 40 元”。
【输出格式】
输出文件共一行,输出最小的总债务规模。
【样例输入 1】
5 3
1 2 10
2 3 1
2 4 1
2
【样例输出 1】
10
【样例输入 2】
4 3
1 2 1
2 3 1
3 1 1
【样例输出 2】
0
【数据范围】
对于 30% 的数据,1 ≤ n ≤ 10,1 ≤ m ≤ 10。
对于 60% 的数据,1 ≤ n ≤ 100, 1 ≤ m ≤ 104。
对于 80% 的数据,1 ≤ n ≤ 104,1 ≤ m ≤ 104。
对于 100% 的数据,1 ≤ n ≤ 106,1 ≤ m ≤ 106。
对于所有的数据,保证 1 ≤ ai, bi ≤ n, 0 < ci ≤ 100。

【题解】

水题,无fuck说

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define jue(a) (((a) >= 0) ? (a) : (-a)) const int INF = 0x3f3f3f3f;
const int MAXN = + ; inline void read(int &x)
{
x = ;char ch = getchar(), c = ch;
while(ch < '' || ch > '') c = ch, ch = getchar();
while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
if(c == '-')x = -x;
} int n,m;
int qian[MAXN], ans;//qian[i]正数表示第i个人被欠多少钱,负数表示欠别人多少钱 int main()
{
scanf("%d %d", &n, &m);
register int tmp1, tmp2, tmp3;
for(register int i = ;i <= m;++ i)
{
read(tmp1), read(tmp2), read(tmp3);
qian[tmp1] -=tmp3;
qian[tmp2] += tmp3;
}
for(register int i = ;i <= n;++ i) ans += jue(qian[i]);
printf("%d", (ans >> ));
return ;
}

T1

B 排列
文件名 输入文件 输出文件 时间限制 空间限制
perm.pas/c/cpp perm.in perm.out 1s 128MB
【题目描述】
小 G 喜欢玩排列。现在他手头有两个 n 的排列。n 的排列是由 0, 1, 2, ..., n − 1
这 n 的数字组成的。对于一个排列 p,Order(p) 表示 p 是字典序第 Order(p) 小的
排列(从 0 开始计数)。对于小于 n! 的非负数 x,P erm(x) 表示字典序第 x 小的
排列。
现在,小 G 想求一下他手头两个排列的和。两个排列 p 和 q 的和为 sum =
P erm((Order(p) + Order(q))%n!)。
【输入格式】
输入文件第一行一个数字 n,含义如题。
接下来两行,每行 n 个用空格隔开的数字,表示小 G 手头的两个排列。
【输出格式】
输出一行 n 个数字,用空格隔开,表示两个排列的和。
【样例输入 1】
2
0 1
1 0
【样例输出 1】
1 0
4
【样例输入 2】
3
1 2 0
2 1 0
【样例输出 2】
1 0 2
【数据范围】
1、2、3、4 测试点,1 ≤ n ≤ 10。
5、6、7 测试点,1 ≤ n ≤ 5000,保证第二个排列的 Order ≤ 105。
8、9、10 测试点,1 ≤ n ≤ 5000。

【题解】

康托展开:

一个序列的排名(从0开始计数) = Rank[n]*(n-1)!+Rank[n-1]*(n-2)!+….
其中Rank[n]表示n位置上的数字在未出现过的数字中的排行,并且从0开始计数。

我们先求出两个序列的康托展开式,相加

但是显然阶乘爆掉

于是我们只加rank数组

如果rank[i]这一位大于等于i,就按i进制进位

证明:

……rank[i] * (i - 1) ! + rank[i + 1] * i !……

若rank[i] > i

那么可分解为

rank[i]%i * (i - 1)! + rank[i]/i * i! + rank[i + 1]*i!

所以进位显然

mod n!的话,只需要忽略rank[i + 1]即可

推式子这一步,我开始想的是类似一遍找一遍插入排序,复杂度n^2

天宇哥哥的做法是  从n往前找,p从-1向上累计,遇到没有用过的p就标记为用过,同时rank[n]--

因为num[i + 1..n]求出后能得知num[i]能选哪一些数   也就是num[1...i]有哪一些数  从小到大枚举到对应排名即可

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdlib> inline void read(int &x)
{
x = ;char ch = getchar(), c = ch;
while(ch < '' || ch > '')c = ch, ch = getchar();
while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
if(c == '-')x = -x;
} const int INF = 0x3f3f3f3f;
const int MAXN = + ; int num1[MAXN], num2[MAXN];
int rank1[MAXN], rank2[MAXN];
int n, b[MAXN]; int main()
{
read(n);
for(register int i = n;i >= ;-- i) read(num1[i]);
for(register int i = n;i >= ;-- i) read(num2[i]);
register int p;
for(register int i = ;i <= n;++ i)
{
p = ;
for(register int j = ;j < i;++ j)if(num1[j] < num1[i]) ++ p;
rank1[i] += p;
p = ;
for(register int j = ;j < i;++ j)if(num2[j] < num2[i]) ++ p;
rank2[i] += p;
rank1[i] += rank2[i];
rank1[i + ] += rank1[i]/i;
rank1[i] %= i;
}
rank1[n] %= n;
for(register int i = n;i >= ;-- i)
{
p = -;
while(rank1[i] >= )
{
++ p;
if(!b[p])-- rank1[i];
}
b[p] = ;
printf("%d ", p);
}
return ;
}

T2

C 剪树枝
文件名 输入文件 输出文件 时间限制 空间限制
tree.pas/c/cpp tree.in tree.out 1s 128MB
【题目描述】
rzyz 有一棵苹果树。苹果树有 n 个节点(也就是苹果),n − 1 条边(也就是
树枝)。调皮的小 G 爬到苹果树上。他发现这棵苹果树上的苹果有两种:一种是黑
苹果,一种是红苹果。小 G 想要剪掉 k 条树枝,将整棵树分成 k + 1 个部分。他
想要保证每个部分里面有且仅有一个黑苹果。请问他一共有多少种剪树枝的方案?
【输入格式】
第一行一个数字 n,表示苹果树的节点(苹果)个数。
第二行一共 n − 1 个数字 p0, p1, p2, p3, ..., pn−2,pi 表示第 i + 1 个节点和 pi 节
点之间有一条边。注意,点的编号是 0 到 n − 1。
第三行一共 n 个数字 x0, x1, x2, x3, ..., xn−1。如果 xi 是 1,表示 i 号节点是黑
苹果;如果 xi 是 0,表示 i 号节点是红苹果。
【输出格式】
输出一个数字,表示总方案数。答案对 109 + 7 取模。
【样例输入 1】
3
0 0
0 1 1
【样例输出 1】
2
【样例输入 2】
6
0 1 1 0 4
1 1 0 0 1 0
【样例输出 2】
1
【样例输入 3】
10
0 1 2 1 4 4 4 0 8
0 0 0 1 0 1 1 0 0 1
【样例输出 3】
27
【数据范围】
对于 30% 的数据,1 ≤ n ≤ 10。
对于 60% 的数据,1 ≤ n ≤ 100。
对于 80% 的数据,1 ≤ n ≤ 1000。
对于 100% 的数据,1 ≤ n ≤ 105。
对于所有数据点,都有 0 ≤ pi ≤ n − 1,xi = 0 或 xi = 1。
特别地,60% 中、80% 中、100% 中各有一个点,树的形态是一条链。

【题解】

做过的第二道树形DP,第一道A了的树形DP。我对树形DP理解还不够深入,所以下面的题解大家自行斟酌,

抱着江信江疑的态度看

正确性请尤其注意需要剪掉的时候,和每一个dp[i][1],能否保证性质:每个连通块有且仅有一个黑点

dp[i][0]表示 i节点不能提供给父亲黑节点的方案数

dp[i][1]表示i节点 能提供给父亲黑节点的而方案书

初始:所有叶节点e,若为黑:dp[e][1] = 1,dp[e][0] = 1(可以切断与父节点连边);若为白:dp[e][1] = 0, dp[e][0] = 1

转移:

若i为黑色节点:

dp[i][1] = πdp[son(i)][0]  这个地方保证了每个连通分块最多有一个黑节点

dp[i][0] = dp[i][1] 即i为黑节点不给父亲黑节点的方案只能是减掉,相当于dp[i][1],保证每个连通分块至少有一个黑节点

上述两条性质,使dp[i][1]的方案保证有且仅有一个黑节点

若i为白色节点:

dp[i][1] = Σ(dp[j][1] * πdp[son(i)][0])  son(i)不含j,j也是i的一个儿子  这个就是一个选黑,另一些选白    保证dp[i][1]的方案有且仅有一个黑节点

dp[i][0] = πdp[son(i)][0] + dp[i][1]  即下面全是白,和能提供黑但减掉与父亲节点的边

答案即为dp[i][1]

正确性我看了很久。。不知道对不对。。还请各位神犇指正

转移有奇淫技巧,见代码及注释

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define max(a, b) ((a) > (b) ? (a) : (b)) inline void read(int &x)
{
x = ;char ch = getchar();char c = ch;
while(ch < '' || ch > '')c = ch, ch = getchar();
while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
if(c == '-')x = -x;
} const int INF = 0X3f3f3f3f;
const int MAXN = + ;
const int MOD = + ; struct Edge
{
int u,v,next;
Edge(int _u, int _v, int _next){u = _u;v = _v;next = _next;}
Edge(){}
}edge[MAXN << ]; int head[MAXN], cnt; inline void insert(int a, int b)
{
edge[++cnt] = Edge(a,b,head[a]);
head[a] = cnt;
} int n,color[MAXN],dp[][MAXN],b[MAXN],fa[MAXN]; /*
若i为黑:
dp[i][0] = dp[i][1]
dp[i][1] = πdp[son][0]

dp[i][0] = πdp[son][0]
dp[i][1] = dp[i][1]
若i为白:
dp[i][0] = πdp[son][0] + dp[i][1]
dp[i][1] = Σdp[son1][1]* πdp[son(不含son1)][0] 可以用dp[i][0]记录 πdp[son][0] 最后判颜色+dp[i][1]
dp[i][1]则记录 Σdp[son1][1]* πdp[son(不含son1)][0]
递推做到On
我们用a,b,c,d表示儿子节点,如果只有a,b,c,式子为:
a1 * b2 * c2 + a2 * b1 * c2 + a2 * b2 * c1
加入d后:
(a1 * b2 * c2 + a2 * b1 * c2 + a2 * b2 * c1) *d2 + a2 * b2 * c2 * d1
其中a2 * b2 * c2可直接用dp[i][0]递推过程值更新 */ void dfs(int u)
{
b[u] = ;
register int size = , sum = , sum2 = , ok = ;
dp[][u] = ;
for(register int pos = head[u];pos;pos = edge[pos].next)
{
int v = edge[pos].v;
if(b[v])continue;
fa[v] = u;
++ size;
ok = ;
dfs(v);
dp[][u] = ((long long)dp[][u] * dp[][v]) % MOD;
dp[][u] += ((long long)dp[][u] * dp[][v]) % MOD;
if(dp[][u] >= MOD)dp[][u] -= MOD;
dp[][u] = ((long long)dp[][u] * dp[][v]) % MOD;
}
if(ok)
{
if(color[u]) dp[][u] = , dp[][u] = ;
else dp[][u] = , dp[][u] = ;
return;
}
if(color[u]) dp[][u] = dp[][u];
else
{
dp[][u] += dp[][u];
if(dp[][u] >= MOD)dp[][u] -= MOD;
}
return;
} int main()
{
read(n);
register int tmp1;
for(register int i = ;i < n - ;++ i) read(tmp1), insert(i + , tmp1 + ), insert(tmp1 + , i + );
for(register int i = ;i < n;++ i) read(color[i + ]);
dfs();
printf("%d", dp[][]);
return ;
}

T3

NOIP模拟 17.8.15的更多相关文章

  1. NOIP模拟17.9.21

    NOIP模拟17.9.21 3 58 145 201 161.5 样例输出21.6 数据规模及约定对于40% 的数据,N <= 20对于60% 的数据,N <= 1000对于100% 的数 ...

  2. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  3. NOIP模拟 17.8.20

    NOIP模拟17.8.20 A.阶乘[题目描述]亲爱的xyx同学正在研究数学与阶乘的关系,但是他喜欢颓废,于是他就制作了一个和阶乘有关系的数学游戏:给出两个整数 n,m,令 t = !n,每轮游戏的流 ...

  4. NOIP模拟 17.8.18

    NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也 ...

  5. NOIP模拟 17.8.16

    NOIP模拟17.8.16 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...

  6. NOIP模拟 17.8.17

    NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 ...

  7. NOIP模拟 17.8.14

    NOIP模拟17.8.14 (天宇哥哥考察细心程度的题) [样例解释]如果删去第一个 1:在[3,1,2]中有 3 个不同的数如果删去 3:在[1,1,2]中有 2 个不同的数如果删去第二个 1:在[ ...

  8. NOIP模拟 17.9.28

    公交车[问题描述]市内有

  9. Noip模拟17 2021.7.16

    我愿称这场考试为STL专练 T1 世界线 巧妙使用$bitset$当作vis数组使用,内存不会炸,操作还方便,的确是极好的. 但是这个题如果不开一半的$bitset$是会炸内存的,因为他能开得很大,但 ...

随机推荐

  1. _strupr _wcsupr _mbsupr

    将字符串转化为大写的形式(Convert a string to uppercase.)定义: char *_strupr( char *string ); wchar_t *_wcsupr( wch ...

  2. router-link动态赋值

    A:router路由配置 export default new Router({ routes: [ { path: '/home', name: 'Home', component: Home, c ...

  3. [转]基于MefBootstrapper的Bootstrapper

    public class Bootstrapper : MefBootstrapper    {        ModuleCatalog moduleCatalog; protected overr ...

  4. 博客的页面定制CSS

    我目前的博客CSS其实也是借用了别家的,来源:https://www.cnblogs.com/Penn000/p/6947472.html 注意使用的模板是:darkgreentrip 复制粘贴使用就 ...

  5. Putty保存设置

    使用putty连接服务器每次都要配置编码,有时候忘了配置,提示就出现中文乱码真是坑爹(纯英文提示也行啊),好了闲话少说,步入正题. Putty的设置保存功能隐藏的实在太好了,原来在Connection ...

  6. 用 vue 脚手架 vue-cli 初始化(新建)项目

    前提:已经安装 node.js 和 git 1.在需要创建的文件夹中,右击 -> Git  Bush Here ,然后输入命令 vue init webpack "文件名"( ...

  7. PAT甲级——A1028 List Sorting

    Excel can sort records according to any column. Now you are supposed to imitate this function. Input ...

  8. Scrapy下载器中间件实现随机请求头和代理ip

    一.设置随机请求头 class UAMiddleWare(object): UA_LIST = [ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; ...

  9. mysqldump mysql数据库导出命令

    mysqldump -u用户名 -p密码 数据库名 > 导出的文件名 例如: mysqldump -uroot -p123456 test > /var/test.sql 如果要压缩就用管 ...

  10. hdu4565

    #include<iostream> #include<cstdio> #include<queue> #include<algorithm> #inc ...