太ex了,哭了哭了orz
后面两道平均一道花了我一天啊!

文章目录

  • D:Vus the Cossack and Numbers
  • 题意翻译
  • 题解
  • 代码实现
  • E:Vus the Cossack and a Field
  • 题意翻译
  • 题解
  • 代码实现
  • F:Vus the Cossack and a Graph
  • 题目
  • 暴力题解
  • 代码实现
  • 官方题解
  • 代码实现

D:Vus the Cossack and Numbers

题意翻译

给定n个和为0实数ai
需要构造一个同样和为0整数序列bi ,使得对于任意i有bi= =⌈ai⌉或bi=⌊ai⌋.其中⌈ai⌉表示大于ai的最小整数,⌊ai⌋表示小于ai的最大整数。输出这个b序列
注意当且仅当ai是整数时,⌊ai⌋=⌈ai⌉.
n (1≤n≤10^5) ,ai( ∣ai∣<10^5).
输入输出样例
输入
4
4.58413
1.22491
-2.10517
-3.70387
输出
4
2
-2
-4
输入
5
-6.32509
3.30066
-0.93878
2.00000
1.96321
输出
-6
3
-1
2
2

题解

没有什么难度,而且这道题是SPJ不用害怕

因为数据保证所有ai的和为0,所有ai的小数加在一起也应该是个整数
且这个a数组最小的和,应该是所有ai向下取整后求和
我们只需要拿到这两个和的差值就意味着有多少个数是向上取整的

只不过特别考虑一下整数即可,因为它向下取整和向上取整对和没有影响

代码实现

#include <cstdio>
#include <cmath>
#define MAXN 100005
#define LL long long
int n;
LL result;
double a[MAXN];
int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ ) {scanf ( "%lf", &a[i] );result += ( LL ) floor ( a[i] );}for ( int i = 1;i <= n;i ++ )if ( ( LL ) ( ceil ( a[i] ) ) == a[i] )printf ( "%d\n", ( int ) a[i] );else if ( result == 0 ) printf ( "%d\n", ( int ) floor ( a[i] ) );else {printf ( "%d\n", ( int ) ceil ( a[i] ) );result ++;}return 0;
}

抓紧时间剩下两道简直了!!!
重点是接下来这一刀!

这道要是我自己做出来了,那可以吹一天!!

E:Vus the Cossack and a Field

题意翻译

给定一个n×m 的 0101 矩阵 a ,定义对矩阵的反转为将矩阵 a 中原来的 0 变为 1 , 1 变为 0 ,得到一个新的矩阵 r ,定义对矩阵的扩展操作为将两个原矩阵 a 的反转分别置于原矩阵的右侧和下方,将原矩阵的复制置于原矩阵的右下角,得到一个二维均为原来的两倍的矩阵,即,若原来的矩阵是 a ,则扩展一次后的矩阵是

a r ​
r a ​

现在将给定的矩阵扩展无数次,得到矩阵 c , q 次询问,每次询问给定 x1,y1,x2,y2,求矩阵中以坐标 (x1,y1) 为左上角, (x2,y2)为右下角的子矩阵中数的和。下标从 1,1 开始。

1≤n,m≤1000 1≤q≤10 ^5
0≤a i,j ≤1
1≤x1≤x2≤10^9, 1≤y1≤y2≤10^9
如:
1 0
1 1
变化第一次后:
1 0 0 1
1 1 0 0
0 1 1 0
0 0 1 1
​变化第二次后:
1 0 0 1 0 1 1 0
1 1 0 0 0 0 1 1
0 1 1 0 1 0 0 1
0 0 1 1 1 1 0 0
0 1 1 0 1 0 0 1
0 0 1 1 1 1 0 0
1 0 0 1 0 1 1 0
1 1 0 0 0 0 1 1
And so on…

输入输出样例
输入
2 2 5
10
11
1 1 8 8
2 4 5 6
1 2 7 8
3 3 6 8
5 6 7 8
输出
32
5
25
14
4
输入
2 3 7
100
101
4 12 5 17
5 4 9 4
1 4 13 18
12 1 14 9
3 10 7 18
3 15 12 17
8 6 8 12
输出
6
3
98
13
22
15
3

题解

首先我们可以定义sum[i][j]表示从1,1到i,j这个矩阵中所有1的个数
(在一个单位矩阵中,即i≤n,j ≤m)
查询的区间不一定是从1,1开始的,所以我们联想到容斥原理
query ( x2, y2 ) - query ( x1 - 1, y2 ) - query ( x2, y1 - 1 ) + query ( x1 - 1, y1 - 1 )
然后把这个矩阵单独抠出来转化为求(1,1,x,y)的矩阵和

我们把每个 n×m 的小矩阵(包括原矩阵和反矩阵)看做一个整体。为了方便表述,矩阵从上到下、从左到右标号为 0 到 ∞(注意不是从 1 开始标号),那么元素 (x,y) 所在的小矩阵为:((x−1)/n,(y−1)/m)

思考一下原矩阵a和变化后的矩阵b,原理上应该是互补的,即它们1的个数应该是n*m
因为b矩阵把a矩阵中的0变成了1,1变成了0嘛!,如图:

我们发现对于任意一行(一列),从左往右(从上往下)每两个分一组,每组内一定是 0 和 1 各一个,即两两匹配。于是我们得到:对于任何一个包含完整小矩阵的前缀矩阵,原矩阵和反矩阵的数量不完全相同。

为什么不完全呢?因为对于奇数个小矩阵的前缀大矩阵,右下角是不确定的,
如图下的第九个绿色矩阵就是不确定的,没有一个完整的矩阵与之配对
排除这种情况后,剩下的一定两两配对!

对于我们一个要求的矩阵,如图:
设 (x,y) 所在小矩阵为 (r=(x−1)/n,c=(y−1)/m),我们将前缀矩阵 (1,1,x,y) 分为若干部分分别求和

1.左上方的绿色部分:答案为 n⋅m⌊r⋅c/2⌋;
如果 r,c 均为奇数,那么对右下角小矩阵分类讨论,根据其正反情况计算答案。
2.左下方、右上方黄色部分:和绿色部分统计方式相同,都是利用两两配对的性质,
对于奇数情况同样分类讨论。
3.右下方红色部分:直接讨论,根据其小矩阵正反情况计算答案。
最难的问题就是怎么讨论它的正负呢?

有一个神仙结论:
设一个小矩阵的坐标为 (x,y),在此特别强调从 0 开始计数(例如上图绿色部分的右下角矩阵坐标为 (2,2)),如果 x和y的二进制的1的个数为奇数,那么该小矩阵为反矩阵
具体为什么,我也十分迷茫!!我也证明不出来

代码实现

由于本宝宝和我的仙女童靴一起研究笔算推导了很久
所以害怕大家看着下面的代码一脸懵逼,
我会尽量把每一个自己曾经迷茫过的细节给大家一一解释!

count就是计算这个特殊矩阵的正反
opt就是算x和y的二进制的1的个数
row算的就是不是一个完整的矩阵,左下方的黄色,如果&1=1就意味着有一个是单的
col算的就是不是一个完整的矩阵,右上方的黄色,如果&1=1就意味着有一个是单的
own算的就是x,y所在的矩阵,红色部分
I就是套的公式,只有r&1&&c&1的时候才会有一个单的完整矩阵!
r,c就是x,y在从0~∞的大矩阵的背景下的坐标

row,col,own中的传值为什么有x-xx或者y-yy
就是减掉完整的矩阵,因为它已经被I算过了

#include <cstdio>
#define MAXN 1005
#define LL long long
int n, m, q;
int sum[MAXN][MAXN];int opt ( int x, int y ) {int totx = 0, toty = 0;while ( x ) {x &= ( x - 1 );totx ++;}while ( y ) {y &= ( y - 1 );toty ++;}return ( ( totx + toty ) & 1 );
}LL count ( int x, int y, int tmp ) {return tmp == 0 ? sum[x][y] : x * y - sum[x][y];
}LL row ( int x, int y, int r, int c ) {int xx = r * n;LL ans = 1LL * c / 2 * m * ( x - xx );if ( c & 1 ) ans += count ( x - xx, m, opt ( r, c - 1 ) );return ans;
}LL col ( int x, int y, int r, int c ) {int yy = c * m;LL ans = 1LL * r / 2 * n * ( y - yy );if ( r & 1 ) ans += count ( n, y - yy, opt ( r - 1, c ) );return ans;
}LL I ( int x, int y, int r, int c ) {LL ans = 1LL * r * c / 2 * n * m;if ( ( r & 1 ) && ( c & 1 ) ) ans += count ( n, m, opt ( r - 1, c - 1 ) );return ans;
}LL own ( int x, int y, int r, int c ) {int xx = r * n, yy = c * m;return count ( x - xx, y - yy, opt ( r, c ) );
}LL query ( int x, int y ) {if ( x == 0 || y == 0 ) return 0;int r = ( x - 1 ) / n, c = ( y - 1 ) / m;if ( r == 0 && c == 0 ) return own ( x, y, r, c );if ( r == 0 ) return row ( x, y, r ,c ) + own ( x, y, r, c );if ( c == 0 ) return col ( x, y, r, c ) + own ( x, y, r, c );return row ( x, y, r, c ) + col ( x, y, r, c ) + I ( x, y, r, c ) + own ( x, y, r, c );
}LL research ( int x1, int y1, int x2, int y2 ) {return query ( x2, y2 ) - query ( x1 - 1, y2 ) - query ( x2, y1 - 1 ) + query ( x1 - 1, y1 - 1 );
}int main() {scanf ( "%d %d %d", &n, &m, &q );for ( int i = 1;i <= n;i ++ ) {for ( int j = 1;j <= m;j ++ ) {int x;scanf ( "%1d", &x );sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + x;}}for ( int i = 1;i <= q;i ++ ) {int x1, x2, y1, y2;scanf ( "%d %d %d %d", &x1, &y1, &x2, &y2 );printf ( "%lld\n", research ( x1, y1, x2, y2 ) );}return 0;
}

F:Vus the Cossack and a Graph

题目

给定nn个节点,mm条边的无向图,记di为第i个点的度。
一个点的度是这个点上连的边数。
Vus需要保留⌈(n+m)/2⌉条边,并保证对于任意一个点i满足f
i ≥⌈di / 2⌉其中fi表示i点在保留的图中的度。
求Vus需要保留哪些边。

暴力题解

首先这个题是可以暴力的,然后随机排序一波后就很难被hack!

代码实现

#include <algorithm>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
#define MAXN 1000005
struct node {int u, v, num;node () {}node ( int U, int V, int Num ) {u = U;v = V;num = Num;}
};
vector < node > G;
int n, m;
int d[MAXN];
int f[MAXN];
bool flag[MAXN];
int main() {scanf ( "%d %d", &n, &m );for ( int i = 1;i <= m;i ++ ) {int u, v;scanf ( "%d %d", &u, &v );G.push_back ( node ( u, v, i ) );d[u] ++;d[v] ++;}for ( int i = 1;i <= n;i ++ )f[i] = ( d[i] + 1 ) >> 1;random_shuffle ( G.begin(), G.end() );int k = m;int p = ( n + m + 1 ) >> 1;for ( int i = 0;i < m && k > p;i ++ ) {int u = G[i].u, v = G[i].v;if ( d[u] == f[u] ) continue;if ( d[v] == f[v] ) continue;d[u] --;d[v] --;k --;flag[i] = 1;}printf ( "%d\n", k );for ( int i = 0;i < m;i ++ )if ( ! flag[i] )printf ( "%d %d\n", G[i].u, G[i].v );return 0;
}

如果就这么水了,这道题就没有存在的价值了!

秉着发扬中华民族传统美德!
富强民主文明和谐,自由平等公正法治,爱国敬业诚信友善!
还是要学会正解哒!亲╭(╯3╰)╮

官方题解

首先就要全开马力消灭下面这个错误的想法:
我们for循环到i,然后就out点i的部分边,这样的你只会保证i满足题意
但是万一i删的边与前面有藕断丝连 地下情,你斩断后说不定前面就满足不了题意

我们要保证i点删的边对前面不会造成答案影响,因而想到了欧拉回路!!
这个点有多少边,就会进多少次栈,每次删一条有关u的边,都会顺便判断一下u

欧拉回路的模板这里就不送上了,
欧拉回路就是每边必须且只遍历一次,起点即是终点
这里是无向边,那么就要保证每个点的度(有多少条边与它相连)是偶数,
这样才能一条边出去一条边回来

所以我们对于输入时是奇数边的点,可以与0建立一条虚无向边
这样每个点包括0都是偶数条边,
不可能存在输入后偶数个是奇数边的点woo!
这里我就不去证,如果有想不懂得,可以留言,我会告诉你为什么

题目也是处处留情登徒浪子 没有讲明是不是完全图,有可能存在多个互不相关的图
就要跑一遍for循环

接下来为了满足留下的边的边数,我们可以保留奇数边,第1,3,5…条边,删掉偶数边
这样就保证了留下边的边数≤(n+m)/2(向上取整)而且也保证了每一个i的f(i)
因为我们跑得是欧拉回路,一个点有多少条边,就会进多少次(边数)/2的栈,
因为一条出去一条回来嘛!这也是为什么选择欧拉回路来做这道题

接下来就是对于实边虚边的保留:
首先虚边使我们擅作主张加的,我们必须消灭作案证据,不能让它出现在大众面前!
所以就算我们保留奇数边,它也必须是个实的!

那么对于偶数边,我们也是尽量删掉虚边,才能尽量满足f,
只要这条边不是虚边,并且它左右两边有一条是虚边,都可以保留这条边
所以只有当这条边和它的左右两边都是实边的时候才迫不得已删掉

代码实现

如果是用vector跑的欧拉回路的话,
一定要注意for循环不药每次都把这个点的每一条边询问一次,会T!!!我被卡了1天
vector又不会跳过边,那么询问到u,通过i这条边递归v,
再次询问到u的时候,一定不会走1~i这些边了
一定都已经处理过了!!
所以帅气又多金的我就用了last来记录一下上一次走到了哪条边(优秀!)

那个opt赋值成2的,小可爱们可以画一个欧拉回路,简单的就可以了
最后你会发现,起点就在栈底,终点就在栈顶,
那么连接栈顶和栈顶-1的这条边的下面一条边就是连接栈底和栈底+1的边

#include <cstdio>
#include <vector>
using namespace std;
#define MAXN 1000005
struct node {int v, edge;node () {}node ( int V, int E ) {v = V;edge = E;}
};
vector < pair < int, int > > result;
vector < node > G[MAXN];
int n, m, cnt, Top;
int d[MAXN];
int last[MAXN];
int tag_time[MAXN];
int sta[MAXN << 2];
bool vis[MAXN << 2];
void dfs ( int u ) {tag_time[u] ++;int ip = tag_time[u];for ( int i = last[u];i < G[u].size();i ++ ) {int v = G[u][i].v, num = G[u][i].edge;last[u] = i + 1;if ( vis[num] ) continue;vis[num] = 1;dfs ( v );if ( tag_time[u] > ip ) break;}sta[++ Top] = u;
}
int main() {scanf ( "%d %d", &n, &m );for ( int i = 1;i <= m;i ++ ) {int u, v;scanf ( "%d %d", &u, &v );cnt ++;G[u].push_back ( node ( v, cnt ) );G[v].push_back ( node ( u, cnt ) );d[u] ++;d[v] ++;}for ( int i = 1;i <= n;i ++ )if ( d[i] & 1 ) {cnt ++;G[i].push_back ( node ( 0, cnt ) );G[0].push_back ( node ( i, cnt ) );}for ( int i = 1;i <= n;i ++ ) {if ( ! tag_time[i] ) {Top = 0;dfs ( i );for ( int j = 1;j + 1 <= Top;j += 2 )if ( sta[j] && sta[j + 1] )result.push_back ( make_pair ( sta[j], sta[j + 1] ) );for ( int j = 2;j + 1 <= Top;j += 2 ) {int opt = j + 2;if ( j + 1 == Top ) opt = 2;if ( ! ( sta[j] && sta[j - 1] && sta[j + 1] && sta[opt] ) && sta[j] && sta[j + 1] )result.push_back ( make_pair ( sta[j], sta[j + 1] ) );}}}printf ( "%d\n", result.size() );for ( int i = 0;i < result.size();i ++ )printf ( "%d %d\n", result[i].first, result[i].second );return 0;
}

好了,还有什么不懂得都可以留言,我会补充出来!
终于把这个恶心的草丛三婊 题给搞定了,下期再见!

【 CF1186D,E,F】Vus the Cossack and Numbers/Vus the Cossack and a Field/Vus the Cossack and a Graph相关推荐

  1. 【EOJ Monthly 2019.02 - F】方差(数学,前缀和,积的前缀和)

    题干: 单测试点时限: 2.0 秒 内存限制: 256 MB "放弃不难,但坚持一定很酷." QQ 小方已经在体育馆苦练一天射箭了,但他还在坚持. QQ 小方每天都要在朋友圈晒自己 ...

  2. 【nowcoder Wannafly挑战赛24 F】 wyf的超级多项式【FFT/NTT】【构造】

    题目传送门 停更已久的blog... orz ckw大佬 我们考虑构造 f f f的递推式.我们设有数组 c c c,满足 f [ n ] = ∑ i = 1 k c [ i ] × f [ n − ...

  3. 【统计学习2】线性回归:RSS,TSS,T检测,F检测,假设检验

    ++++++++++++++++++++++ 参考众多文章 ++++++++++++++++++++++ 第一:假设检验 以抛硬币来说 H0 假设[假设]:硬币是公平[出现正反概率各为1/2] Ha ...

  4. 洛谷 2 月月赛 I 『MdOI R4』 (Div2) A ~ D 四题全,也许会有六题,超高质量题解 (Div.1E、F下辈子一定补)【每日亿题2 / 9】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A.P7337 『MdOI R4』Fun B.P7338 『MdOI R4』Color C.P7 ...

  5. 【详解】某企业的培训关系模式 R(培训科目,培训师,学生,成绩,时间,教室), R的函数依赖集 F={培训科目→→培训师,(学生,培训科目)→成绩,(时间,教室)→培训科目,(时间,培训师)→

    某企业的培训关系模式 R(培训科目,培训师,学生,成绩,时间,教室), R的函数依赖集 F={培训科目→培训师,(学生,培训科目)→成绩,(时间,教室)→培训科目,(时间,培训师)→教室,(时间,学生 ...

  6. 【POJ/算法】 3259 Wormholes(Bellman-Ford算法, SPFA ,FLoyd算法)

    Bellman-Ford算法 Bellman-Ford算法的优点是可以发现负圈,缺点是时间复杂度比Dijkstra算法高.而SPFA算法是使用队列优化的Bellman-Ford版本,其在时间复杂度和编 ...

  7. szu 寒训第二天 树状数组 二维树状数组详解,以及树状数组扩展应用【求逆序对,以及动态第k小数】

    树状数组(Binary Index Tree) 树状数组可以解决可以转化为前缀和问题的问题 这是一类用以解决动态前缀和的问题 (有点像线段树简版) 1.对于 a1 + a2 + a3 + - + an ...

  8. 【最强ResNet改进系列】Res2Net:一种新的多尺度网络结构,性能提升显著

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要15分钟 Follow小博主,每天更新前沿干货 [导读]2020年,在各大CV顶会上又出现了许多基于ResNet改进的工作,比如:Res2Ne ...

  9. 批量(导入导出)迁移AD中的用户信息和密码到新环境中,同时保持用户在MOSS中的权限【addusers,ldifde,copypwd,UserInfo,tp_SystemID】...

    工具介绍: 1.ldifde是系统自带命令行工具,直接在cmd就可以运行. 2.addusers是在wind2k resource kit中的命令工具,可以通过安装wind2k resource ki ...

最新文章

  1. c语言单词复数,C语言关于复数
  2. [OSDI 16] Wukong : 基于RDMA的高并发、快速的分布式RDF Graph Query系统
  3. 【java】java开发中的23种设计模式详解
  4. sklearn训练模型保存与加载
  5. Python基础学习四 函数
  6. Redmine 数据库连接错误
  7. Linux用户组笔记整理
  8. Android官方开发文档Training系列课程中文版:多样屏幕之支持不同的屏幕尺寸
  9. 再见李佳奇,菜鸟哥用Python也能帮小姐姐选择口红啦,快来看看!!
  10. Spark源码分析之Master主备切换机制
  11. linux r后台执行,screen 命令简单用法 Linux后台执行 就用它
  12. 2018-3-10 unset 变量 ab测试
  13. 2017 年,阿里巴巴开源的那些事儿
  14. 给DateField和DateChooser进行汉化
  15. 九宫幻方(蓝桥)深搜
  16. mysql返回上一层_mysql常用命令大全
  17. 九段系统服务器,人力资源一卡通考勤系统
  18. route -n 详解
  19. Android自定义dialog对话框悬浮在界面上
  20. php c语言扩展名,c语言源程序的扩展名是什么

热门文章

  1. iPhone同步助手 V3.2.7.2 中文官方版
  2. 混合面向目标的机器人
  3. 高鹏清华计算机系,丁高鹏:强身健体为祖国健康工作五十年-清华大学新闻网...
  4. 超级好用的视频转换器Cisdem Video Converter for Mac
  5. java对象的访问定位_深入理解java虚拟机---对象的访问定位(十)
  6. js解决chrome浏览器无法自动播放音频
  7. windows下Ubuntu使用chmod提示No such file or directory
  8. 有数字要生成条形码生成器_如何制作自己的“意外”数字生成器
  9. 搞一下整车以太网技术 | A1 整车以太网技术概述
  10. Ubuntu系统安装LAMP应用Discuz 建设论坛网站