昨晚的9点的CF,DIV2专场,为了rating change开了小号去。
说起来上一场也是DIV2专场开的小号去参加,然后第一个小号就上1900了,昨晚打完之后第二个小号也上DIV1了。蛮开心的。
最近这段时间在家里大概是参加不了12点半的CF了。毕竟补充睡眠。
部分题解:
Codeforces 707A Brain's Photos
题目链接:http://www.codeforces.com/problemset/problem/707/A
题意:给一个矩阵,判断矩阵里面有没有出现除了B,W,G之外的字母。
分析:水题,扫描一遍判断即可。
咳咳,刚开始比赛的时候刚打完DOTA人不清醒,题目没看完就去敲了,没看到G也算,只判断了B和W,结果竟然水过了测试数据。后来被人HACK之后重新看了一遍题意大骂自己傻X。
<span style="font-size:18px;">/***********************************************
|Author: Fry
|Created Time: 2016/8/20 20:59:40
|File Name: A.cpp
|Copyright:
| For personal use, feel free to use
| Otherwise call me at http://blog.csdn.net/fry_guest
***********************************************/
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
char c;
bool f=false;
while (~scanf("%d%d",&n,&m)){
f=false;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
scanf(" %c",&c);
if (c!='B'&&c!='W'&&c!='G') f=true;
}
}
if (f) printf("#Color\n");
else printf("#Black&White\n");
}
return 0;
}
</span>
Codeforces 707B Bakery
题目链接:http://www.codeforces.com/problemset/problem/707/B
题意:给一张图,有重边。其中某些点已经被标记,要求找到一个未被标记的点,使得其距离最近的标记过的点的距离最小。输出最小距离,若不存在这样的点输出-1。
分析:反证法可以得出,最终答案一定和一个标记的点相邻。
那么只要枚举所有标记过的点,再枚举其所有的相邻的点即可。
写的时候不是很清醒,代码挺丑。
<span style="font-size:18px;">/***********************************************
|Author: Fry
|Created Time: 2016/8/20 21:15:37
|File Name: B.cpp
|Copyright:
| For personal use, feel free to use
| Otherwise call me at http://blog.csdn.net/fry_guest
***********************************************/
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct point
{
int x,c;
point (int _x=0,int _c=0){
x=_x; c=_c;
}
};
vector<point>v[N];
bool check[N];
int ans;
void DW(int x)
{
for (int i=0;i<v[x].size();i++){
if (!check[v[x][i].x]){
if (ans==-1){
ans=v[x][i].c;
}
else ans=min(v[x][i].c,ans);
}
}
}
int main()
{
int n,m,k;
int l,r,c;
while (~scanf("%d%d%d",&n,&m,&k)){
for (int i=1;i<=n;i++) v[i].clear();
for (int i=1;i<=m;i++) {
scanf("%d%d%d",&l,&r,&c);
v[l].push_back(point(r,c));
v[r].push_back(point(l,c));
}
memset(check,0,sizeof(check));
for (int i=1;i<=k;i++){
scanf("%d",&c);
check[c]=1;
}
ans=-1;
for (int i=1;i<=n;i++){
if (check[i]){
DW(i);
}
}
printf("%d\n",ans);
}
return 0;
}
</span>
Codeforces 707C Pythagorean Triples
题目链接:http://www.codeforces.com/problemset/problem/707/C
题意:已知直角三角形的一条边,求可能的另外两条边。三条边均为正整数,n<1e9,要求最终结果小于1e18。无解时输出-1
分析:很容易可以得知,当给出的边长度小于3时无解.
那么接下来,我们假设给出的边为一条直角边。另外两条边长分别为a,b,其中b是斜边
由勾股定理可以得出:a*a+n*n=b*b
公式稍作调整:(b-a)(b+a)=n*n
当n为奇数时,只需要使得b-a=1,b+a=n*n即可。
当n为偶数时,只需要使得b-a=2,b+a=n*n/2即可。
写完之后计算一下极限数据,偶数和奇数分别大概是2.5e17和5e17,不会超过上限。
<span style="font-size:18px;">/***********************************************
|Author: Fry
|Created Time: 2016/8/20 21:26:03
|File Name: C.cpp
|Copyright:
| For personal use, feel free to use
| Otherwise call me at http://blog.csdn.net/fry_guest
***********************************************/
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long n,a,b;
while (~scanf("%I64d",&n)){
if (n<3){
printf("-1\n");
continue;
}
if (n%2){
a=n*n/2;
b=a+1;
printf("%I64d %I64d\n",a,b);
}
else {
a=n*n/2/2-1;
b=a+2;
printf("%I64d %I64d\n",a,b);
}
}
return 0;
}
</span>
Codeforces 707D Persistent Bookcase
题目链接:http://www.codeforces.com/problemset/problem/707/D
题意:有一个有n行m列的书架,初始为空,现有q次操作,要求输出每次操作完之后书架上共有几本书。
操作分为4种:
1.在第i行第j列放入一本书。如果在操作之前第i行第j列已经有书了,那么忽略此次操作。
2.将第i行第j列的书拿走。如果在操作之前第i行第j列没有书,那么忽略此次操作。
3.将第i行的所有书反转。就是对于第i行的所有列,如果这个位置有书,那么将它拿走,如果这个位置没有书,那么放一本书到这个位置。
4.将现在的整个书架的状态返回到第k次操作完之后的样子。
1<=n,m<=1e3,1<=q<=1e5
分析:其实原题面有提到过持久化数据结构,听队友说她这题直接写了持久树就A了。
我没想到持久树(好吧其实是不会写),用了点方法过去了。
将所有的操作建成为一棵树,然后在树上操作就简单了。
首先根节点一定是第0次操作,也就是初始值为空,对于之后的第i个操作,如果这个操作不是操作4,那么它的父亲节点是第i-1个操作,如果这个操作是操作4并且是回到第k次操作完之后的样子,那么这个节点的父亲是第k次操作。
建完树之后进行一次树的遍历。回溯的时候要把原有的操作删除。
需要注意的是原有的操作可能并不存在,比如原本第i行第j列已经有书了,这次操作又要求在这个位置添加一本书,那么就不会进行操作,同样回溯的时候也不能将这本书拿走。
关于内存,队友用持久化能直接过的话,实际上n*q的内存是毫无问题的。我的方法的内存是O(min(q,n*m))。
时间复杂度,暴力操作的话,添加和删除操作的复杂度是O(1),反转的复杂度是O(m),虽然感觉O(q*m)也能过的样子,
不过我还是换了个姿势,记录的时候用了一个标记来记录每一行的反转情况,并且每一行开一个set来记录有哪些位置有书,这样最终时间复杂度,添加和删除操作是O(logm),反转的复杂度是O(1),最终复杂度O(q*logm)
<span style="font-size:18px;">/***********************************************
|Author: Fry
|Created Time: 2016/8/20 21:37:29
|File Name: D.cpp
|Copyright:
| For personal use, feel free to use
| Otherwise call me at http://blog.csdn.net/fry_guest
***********************************************/
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int ans[N],t[N],x[N],y[N];
set<int>s[N];
vector<int>v[N];
bool check[N];
int n,m;
void DW(int a,int sum)
{
bool f=false;
if (t[a]!=4){
if (t[a]==3) {
f=true;
if (!check[x[a]]) sum-=s[x[a]].size();
else sum-=m-s[x[a]].size();
check[x[a]]=!check[x[a]];
if (!check[x[a]]) sum+=s[x[a]].size();
else sum+=m-s[x[a]].size();
}
else if (t[a]==2) {
if (!check[x[a]]){
if (s[x[a]].find(y[a])!=s[x[a]].end()){
s[x[a]].erase(y[a]);
sum--;
f=true;
}
}
else {
if (s[x[a]].find(y[a])==s[x[a]].end()){
s[x[a]].insert(y[a]);
sum--;
f=true;
}
}
}
else if (t[a]==1) {
if (!check[x[a]]){
if (s[x[a]].find(y[a])==s[x[a]].end()){
s[x[a]].insert(y[a]);
sum++;
f=true;
}
}
else {
if (s[x[a]].find(y[a])!=s[x[a]].end()){
s[x[a]].erase(y[a]);
sum++;
f=true;
}
}
}
}
ans[a]=sum;
for (int i=0;i<v[a].size();i++){
DW(v[a][i],sum);
}
if (f){
if (t[a]==3)check[x[a]]=!check[x[a]];
if (t[a]==2){
if (!check[x[a]]) s[x[a]].insert(y[a]);
else s[x[a]].erase(y[a]);
}
if (t[a]==1){
if (!check[x[a]]) s[x[a]].erase(y[a]);
else s[x[a]].insert(y[a]);
}
}
}
int main()
{
int q;
while (~scanf("%d%d%d",&n,&m,&q)){
memset(check,0,sizeof(check));
for (int i=0;i<=n;i++) v[i].clear();
for (int i=0;i<=n;i++) s[i].clear();
for (int i=1;i<=q;i++){
scanf("%d",&t[i]);
if (t[i]<3){
scanf("%d%d",&x[i],&y[i]);
}
else scanf("%d",&x[i]);
}
for (int i=1;i<=q;i++){
if (t[i]==4){
v[x[i]].push_back(i);
}
if (i!=q&&t[i+1]!=4){
v[i].push_back(i+1);
}
}
if (t[1]!=4){
v[0].push_back(1);
}
for (int i=0;i<v[0].size();i++){
DW(v[0][i],0);
}
for (int i=1;i<=q;i++){
printf("%d\n",ans[i]);
}
}
return 0;
}
</span>