Codeforces Round #626 (Div. 2)
A
这个似乎出过一遍了?选一个偶数或者两个奇数。
B
题意:
给你nnn个数a1,a2,a3,a4......ana_1,a_2,a_3,a_4......a_na1,a2,a3,a4......an
再给你mmm个数b1,b2.....bmb_1,b_2.....b_mb1,b2.....bm
有一个矩形n⋅mn\cdot mn⋅m 的矩形C,Ci,j=ai⋅bjC_{i,j}=a_i\cdot b_jCi,j=ai⋅bj,且a,ba,ba,b中的数不是0,就是1,所以C中也是不是零就是1。
现在给你一个kkk,让你输出C中面积为kkk的矩形个数。
思路:
这个题目怎么说呢,说好想也好像,说不好想也不好想。。。。
首先,因为a,ba,ba,b中不是零就是1,所以C中为1的区域肯定是矩形,且大小为aaa中连续1的个数 * bbb中连续1的个数,有疑问可以画一下,到这儿还是比较好想的。然后接下来是重点。
假设a产生的连续的段为x1,x2.....xcnt1x_1,x_2.....x_{cnt1}x1,x2.....xcnt1
b产生连续的段为y1,y2,y3....ycnt2y_1,y_2,y_3....y_{cnt2}y1,y2,y3....ycnt2
这可以构成cnt1⋅cnt2cnt1\cdot cnt2cnt1⋅cnt2个矩形。
我们先按正解来,对于面积kkk的矩形,我们枚举边长,<x,y><x,y><x,y>
然后提前预处理好aaa中段对x的贡献,每一个为xi−x+1x_i-x+1xi−x+1;同理yyy也是这样。
答案就是∑i=1cnt1(xi−x+1)⋅∑i=1cnt2(yi−y+1)\sum\limits_{i=1}^{cnt1}(x_i-x+1)\cdot \sum\limits_{i=1}^{cnt2}(y_i-y+1)i=1∑cnt1(xi−x+1)⋅i=1∑cnt2(yi−y+1)。对于枚举边长,复杂度O(N)O(N)O(N),预处理时间复杂度也是O(N)O(N)O(N)。
这样想似乎这个题目也就这样。。。。
但在比赛中我没想到直接枚举面积为kkk的矩形边长,而是枚举的a∗ba*ba∗b中可以产生的矩形,正如上文所说,a,ba,ba,b可以构成矩形为cnt1⋅cnt2cnt1\cdot cnt2cnt1⋅cnt2个。对于每个矩形我们算面积为kkk的贡献,怎么算呢?对于每个矩形xi⋅yix_i\cdot y_ixi⋅yi,也是枚举边长,不过是枚举xix_ixi的边长,看其是否可以构成面积为kkk的矩形,这里假设枚举xix_ixi的边长为xxx,那么y=k/xy=k/xy=k/x。那么xi⋅yix_i\cdot y_ixi⋅yi可以产生<x,y><x,y><x,y>的贡献为(xi−x+1)⋅(yi−y+1)(x_i-x+1)\cdot (y_i-y+1)(xi−x+1)⋅(yi−y+1)。其中xxx的范围[1,xi][1,x_i][1,xi]。我们不断累加贡献,也能得到贡献,但这样随机数据尚可,但最坏会被卡成n2n^2n2。值的一提的是我一开始看错范围以为4000。。。一直Wa和T,后经ZHJ提醒,数组开到40000,竟然以998ms的时间卡过,虽说后来重测被卡掉,但是这也不失是一件趣事。
赛后我以我的思路印证题解中代码,一直对上面正解中预处理边长累加那儿有疑惑,这很矛盾,在我的思路中,是枚举矩形然后对于这个矩形,在枚举边长,贡献是相乘后在相加,而题解中是相加后在相乘,这可能对别人来说很容易想透的,但对于我而言,这有点无法接受,人和人之间的思维方式真的有差别。
我按我的方式进行了思考,发现这两种思路是殊途同归的。我将用我的思路来解释正解。
假设aaa数组又连续段a1,a2a_1,a_2a1,a2,b数组有连续段b1,b2b_1,b_2b1,b2
我们可以构造a1a_1a1xb1b_1b1,a1a_1a1xb2b_2b2,a2a_2a2xb1b_1b1,a2a_2a2xb2b_2b2,四个矩形,原来是对每个矩形枚举边会超时,现在是对面积为kkk的矩形我们找边<x,y><x,y><x,y>
然后这四个矩形对其产生的贡献为
(a1−x+1)⋅(b1−y+1)+(a1−x+1)⋅(b2−y+1)+(a2−x+1)⋅(b1−y+1)+(a2−x+1)⋅(b2−y+1)(a_1-x+1)\cdot (b_1-y+1)+(a_1-x+1)\cdot (b_2-y+1)+(a_2-x+1)\cdot(b_1-y+1)+(a_2-x+1)\cdot (b_2-y+1)(a1−x+1)⋅(b1−y+1)+(a1−x+1)⋅(b2−y+1)+(a2−x+1)⋅(b1−y+1)+(a2−x+1)⋅(b2−y+1)
我们对上述式子进行提取公因式得
((a1−x+1)+(a2−x+1))⋅((b1−y+1)+(b2−y+1))((a_1-x+1)+(a_2-x+1))\cdot ((b_1-y+1)+(b_2-y+1))((a1−x+1)+(a2−x+1))⋅((b1−y+1)+(b2−y+1))
这个式子就是说对于边<x,y><x,y><x,y> 结果是,a中所有段对xxx产生的贡献相加 乘以 b中所有段对yyy产生贡献的累加,这里所说的贡献可以当做产生多少xxx,产生多少yyy。
bool a[N],b[N];
ll q[N],p[N];
void init(int n,int m){ int cnt1(0),cnt2(0);rep(i,1,n){if(a[i] == 0){for(int j =1 ;j <= cnt1;++j){q[j] += cnt1 - j + 1;}cnt1 = 0;}else cnt1 ++;}if(cnt1){rep(j,1,cnt1) q[j] += cnt1 - j + 1;} rep(i,1,m){if(b[i] == 0) {for(int j = 1;j <= cnt2;++j) p[j] += cnt2 - j + 1;cnt2 = 0;}else cnt2++;}if(cnt2){rep(j,1,cnt2) p[j] += cnt2 - j + 1;}
}
int main(){int n = read(),m = read(),k =read();rep(i,1,n) a[i] = read();rep(i,1,m) b[i] = read();init(n,m); ll ans = 0;for(int i = 1;i <= n;++i){if(k % i == 0){int x = i,y = k/i;if(y <= m) ans += q[x]*p[y];}}cout<< ans;
}
C
题意:
就是括号匹配,但是现在的问题是你可以通过对任意[l,r][l,r][l,r]排序,代价是这段的长度,来使的括号匹配。
思路:
首先就是若左右括号不等则一定不能匹配,否则一定可以。
我们设一个栈,然后从头遍历每个字符。
我们知道括号匹配的形式是()()(),所以我们考虑当前字符是否是’(’,如果是的话,看栈顶元素是否是’)’,如果是的话,这说明可以将这两个字符排序可以正确匹配,所以我们将ans+=2ans+=2ans+=2,并且删除栈顶元素;不是的话就将’(‘入栈。
如果当前元素是’)’ ,看栈顶是否是’('是的话就删除栈顶元素;否则入栈。
我们发现这样的匹配思路并没有错,而且代码还很好写。具体的怎么的正确我曾尝试证明,但是失败了。
stack<char> st;
int main(){int n = read();string s;cin >> s;int l = s.size();int cnt1(0),cnt2(0);rep(i,0,l-1){if(s[i]=='(') cnt1++;else cnt2++;}if(cnt1!=cnt2) return puts("-1"),0;int ans = 0;rep(i,0,l-1){if(s[i] =='('){if(st.size()&&st.top()==')'){st.pop();ans+=2;}else st.push('(');}else if(st.size()&&st.top()=='(') st.pop();else st.push(s[i]);}cout <<ans;
}
D
题意:
给你nnn个数,a1,a2,a3.....ana_1,a_2,a_3.....a_na1,a2,a3.....an。然后问你两两之和的异或和是多少。
思路:
一般关于位运算的题目都是按位处理,我一开始想两两之和,那么从低到高统计1的个数,那么这一位1的个数乘0的个数,为当前为两两相加会产生1的个数,如果是奇数就对答案产生贡献,但是会有进位产生,不知道怎么处理。
题解给的方法很好,转化到了另一个问题,不用考虑进位了。
对于结果来说,第kkk位是否为1,与kkk之后位没有关系,所以直接%2k+1\%2^{k+1}%2k+1,去掉之后的位。
那么想要答案第kkk位为1的话,会有奇数个这样的项(ai+aj)(a_i+a_j)(ai+aj)会在第kkk位为1。而对于ai+aja_i+a_jai+aj来说,怎么判断它第kkk为是否为1呢?
我们分类讨论
1、ai,aja_i,a_jai,aj第kkk为上都没有1,那么若使得第kkk为上是1,则是下面这种:
最小:2k2^k2k
k+1 | k | k-1 | k-2 | 0 |
---|---|---|---|---|
0 | 0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 1 | 0 | 0 | 0 |
最大:2k+1−22^{k+1}-22k+1−2
k+1 | k | k-1 | k-2 | 0 |
---|---|---|---|---|
0 | 0 | 1 | 1 | 1 |
0 | 0 | 1 | 1 | 1 |
0 | 1 | 1 | 1 | 0 |
2、kkk上至少有一位为1
最小:2k2^k2k
k+1 | k | k-1 | k-2 | 0 |
---|---|---|---|---|
0 | 1 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 0 |
最大:2k+1−12^{k+1}-12k+1−1 (因为第kkk位上有一个1,为了不能产生进位,所以后面不能有进位,所以相加后的最大值后面全是1)
k+1 | k | k-1 | k-2 | 0 |
---|---|---|---|---|
0 | 1 | 1 | 1 | 1 |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 1 | 1 |
3、kkk上全为1
最小:2k+1+2k2^{k+1}+2^k2k+1+2k
k+1 | k | k-1 | k-2 | 0 |
---|---|---|---|---|
0 | 1 | 1 | 0 | 0 |
0 | 1 | 1 | 0 | 0 |
1 | 1 | 0 | 0 | 0 |
最大:2k+2−22^{k+2}-22k+2−2
k+1 | k | k-1 | k-2 | 0 |
---|---|---|---|---|
0 | 1 | 1 | 1 | 1 |
0 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
综上,若ai+aja_i+a_jai+aj相加结果在[2k,2k+1−1][2^k,2^{k+1}-1][2k,2k+1−1] 或者[2k+1+2k,2k+2−2][2^{k+1}+2^k,2^{k+2}-2][2k+1+2k,2k+2−2]。则会在第kkk位上贡献1。
我们对于每一位,把模后的结果放到一个数组里,并从小到大排序,对于每个iii,二分查找即可。
(这个二分我tm快改了一晚上,好吧,就是一晚上。。。。
int a[N];
vector<int> q;
int n;
int bina1(int x,int m,int num){//查询 <= num 的最大值int l = x+1,r = m;while(l < r){int mid = l + r +1 >> 1;if(q[x] + q[mid] <= num) l = mid;else r = mid -1;}return l;}
int bina2(int x,int m,int num){//查询 >= num的最小值int l = x+1,r = m;while(l < r){int mid = l + r >>1;if(q[mid]+q[x] >= num) r = mid;else l = mid + 1;}return r;
}
bool ok(int p){//p为2^{k+1}q.clear();rep(i,1,n) q.push_back(a[i]%p);sort(q.begin(),q.end());int S = q.size();ll ans = 0;for(int i = 0;i < S-1;++i){//若区加相交,则可二分查找if(q[i+1]+q[i]<=p-1&&q[S-1]+q[i]>=p/2) ans += bina1(i,S-1,p-1) - bina2(i,S-1,p/2)+1;if(q[i+1]+q[i]<=p*2 -2&&q[S-1]+q[i]>=p+p/2) ans += bina1(i,S-1,p*2-2) - bina2(i,S-1,p+p/2)+1;}if(ans&1) return 1;//奇数个则产生贡献else return 0;
}
int main(){n = read();rep(i,1,n) a[i] = read();if(n == 2) return cout << (a[1]+a[2]) <<endl,0;ll ans = 0;for(int i = 0;i <= 25;i ++){if(ok(1<<(i+1))) ans |= 1<<i;}cout << ans;
}
Codeforces Round #626 (Div. 2)相关推荐
- Codeforces Round #626 (Div. 2) D. Present 按位贡献 + 快排新姿势
传送门 文章目录 题意: 思路: 题意: 给你一个长度为nnn的序列aaa,让你计算 n≤4e5,a≤1e7n\le 4e5,a\le 1e7n≤4e5,a≤1e7 思路: 首先这个式子是n2n^2n ...
- Codeforces Round #777 (Div. 2) 简训
Codeforces Round #777 (Div. 2) 简训 导语 涉及的知识点 题目 A Madoka and Math Dad B Madoka and the Elegant Gift C ...
- Codeforces Round #815 (Div. 2)
Codeforces Round #815 (Div. 2) 传送门 :Codeforces Round #815 (Div. 2) 之前都是108键的键盘,最近在家用的68,两三天了还是非常不顺手, ...
- Codeforces Round #281 (Div. 2) A. Vasya and Football 模拟
A. Vasya and Football 题目连接: http://codeforces.com/contest/493/problem/A Description Vasya has starte ...
- F. Bouncy Ball(Codeforces Round 859 (Div. 4))
题目链接:Problem - F - Codeforceshttps://codeforces.com/contest/1807/problem/F 题意:给你一个n*m大小的网格,再给你一个起始点和 ...
- D. Boboniu Chats with Du(Codeforces Round #664 (Div. 2) )
感受 怎么这么傻逼的题目,我现场A不了呢?看来还有不少提升的空间怎么这么傻逼的题目,我现场A不了呢?看来还有不少提升的空间怎么这么傻逼的题目,我现场A不了呢?看来还有不少提升的空间 题意 简单来说,给 ...
- F. Strange Array(Codeforces Round #727 (Div. 2))(主席树)
F. Strange Array 给定一个长度为nnn的数组aaa,1≤ai≤n1 \leq a_i \leq n1≤ai≤n,对于每个aia_iai,我们要找到一个l≤i,r≥il \leq i ...
- E. Company(Codeforces Round #520 (Div. 2))
E. Company 给定一颗有nnn个节点的树,有mmm次询问,每次询问给定[l,r][l, r][l,r],我们可以选择删除其中的一个点ppp,然后找到一个深度最深的rtrtrt,使得剩下的点都在 ...
- D. Cut and Stick(Codeforces Round #716 (Div. 2))
D. Cut and Stick 给定一个长度为nnn的数组,里面元素为a1,a2,a3,-,an−1,an,(1≤ai≤n)a_1, a_2, a_3, \dots, a_{n- 1}, a_n, ...
最新文章
- 【c语言】蓝桥杯基础练习 特殊的数字
- SQL判断NULL的几种常见方式
- max的贴图烘焙技术简易流程
- Mac查看Android动态库依赖
- vlc学习计划(5)--VLC程序宏及线程分析
- STL中算法锦集(四)
- Github continuous deployment (CD) 最佳实践
- 怎么样开会才有效果?
- 【转】超详细的UML状态图符号,初学者也能轻松看懂状态图
- gradle下bug修正后问题仍存在解决思路
- 如何提高PHP代码的质量?第二部分 单元测试
- 将一正整数序列{K1,K2,…,K9}重新排成一个新的序列。新序列中,比K1小的数都在K1的左面(后续的再向左存放),比K1大的数都在K1的右面(后续的再向右存放),从K1向右扫描
- delphi生产者消费者模式代码_并发设计模式:生产者-消费者模式,并发提高效率...
- mysql中关于关联索引的问题——对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引?...
- html可折叠边栏,html – 仅使用CSS的可折叠灵活宽边栏
- linux aio拷贝文件,Linux通过AIO进行异步读文件
- 微信小程序获取用户信息并存入数据库
- python中的unicode码是什么_Python中Unicode字符串
- Quartz插件配置-005
- The full stack trace of the root cause is available in the server logs.