COCI 2018/2019 CONTEST #2 Solution
Problem1 Preokret
第一题一定不是什么难题。
第一个问题在读入的时候判断当前时间是不是在1440及以前就行
第二个问题考虑离线处理,由于每个时刻只能最多发生1个事件那么就弄个桶记录每一个事件就行了。
水过T1。
Code:
- # include <bits/stdc++.h>
- using namespace std;
- const int N=;
- int a[N];
- int A,B,T,rec1,rec2;
- template <typename T>inline void read(T &x)
- {
- int w=,X=; char c=;
- while (c<''||c>'') w|=c=='-',c=getchar();
- while (c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
- x=w?-X:X;
- }
- int main()
- {
- // freopen("Preokret.in","r",stdin);
- // freopen("Preokret.out","w",stdout);
- memset(a,-,sizeof(a));
- read(A);
- for (int i=;i<=A;i++) read(T),a[T]=;
- read(B);
- for (int i=;i<=B;i++) read(T),a[T]=;
- int Ans1=,Ans2=,flag=-,s1=,s2=;
- for (int i=;i<=;i++) {
- if (a[i]==-) continue;
- if (a[i]==) s1++; else s2++;
- if (i<=) Ans1++;
- if (flag==-) { flag=s1<s2; continue;}
- if (s1>s2&&flag==) flag=,Ans2++;
- else if (s1<s2&&flag==) flag=,Ans2++;
- }
- cout<<Ans1<<'\n'<<Ans2<<'\n';
- return ;
- }
Problem2 Kocka
这个题对于100%的数据一定不是O(n2)的构造,而是数学的判断。
我们可以简单考虑四种情况,我们记四个数组分别是left[],right[],up[],down[],
分别考虑四个数组元素值是x的时候代表什么含义,
以left[i]为例,left[i]=-1的时候表示第i行没有放东西,那么对应的right[i]必须也是-1否则构造不合法,而对于up[]和down[]无影响。
left[i]=x(x≠-1时),那么意味着在(i,x+1)这个位置必须存在一个障碍物,那么从上面看下来可以看到的不能大于i-1吧,下面看上来不能超过n-i吧,右边看过来不能超过n-x-1吧。
对于 right[]和up[]和down[]同理。
这里需要注意在C++中up什么的可能是保留字,我Define了一下。
Code
- # include <bits/stdc++.h>
- # define fp(i,s,t) for (int i=s;i<=t;i++)
- # define left Left
- # define right Right
- # define up Up
- # define down Down
- using namespace std;
- const int N=1e5+;
- int left[N],right[N],up[N],down[N],n;
- inline void read(int &x)
- {
- int w=,X=; char c=;
- while (c<''||c>'') w|=c=='-',c=getchar();
- while (c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
- x=w?-X:X;
- }
- bool work()
- {
- fp(i,,n) {
- if (left[i]==-) {
- if (right[i]==-) continue;
- return ;
- }
- if (up[left[i]+]==-||up[left[i]+]>i-) return ;
- if (down[left[i]+]==-||down[left[i]+]>n-i) return ;
- if (right[i]==-||right[i]>n-left[i]-) return ;
- }
- fp(i,,n) {
- if (up[i]==-) {
- if (up[i]==-) continue;
- return ;
- }
- if (left[up[i]+]==-||left[up[i]+]>i-) return ;
- if (right[up[i]+]==-||right[up[i]+]>n-i) return ;
- if (down[i]==-||down[i]>n-up[i]-) return ;
- }
- fp(i,,n) {
- if (right[i]==-) {
- if (left[i]==-) continue;
- return ;
- }
- if (up[n-right[i]]==-||up[n-right[i]]>i-) return ;
- if (down[n-right[i]]==-||down[n-right[i]]>n-i) return ;
- if (left[i]==-||left[i]>n-right[i]-) return ;
- }
- fp(i,,n) {
- if (down[i]==-) {
- if (up[i]==-) continue;
- return ;
- }
- if (left[n-down[i]]==-||left[n-down[i]]>i-) return ;
- if (right[n-down[i]]==-||right[n-down[i]]>n-i) return ;
- if (up[i]==-||up[i]>n-down[i]-) return ;
- }
- return ;
- }
- int main()
- {
- // freopen("Kocka.in","r",stdin);
- // freopen("Kocka.out","w",stdout);
- read(n);
- fp(i,,n) read(left[i]);
- fp(i,,n) read(right[i]);
- fp(i,,n) read(up[i]);
- fp(i,,n) read(down[i]);
- puts(work()?"DA":"NE");
- return ;
- }
Problem3 Deblo
这个题是树上路径计数,初步搞搞O(n2log2 n)暴力还是搞得来的。
但是书上路径统计想到了淀粉质点分治暴力统计路径。
这里需要注意点分治的一般步骤:
每次在子树里面选定一个重心,考虑一条过重心的路径,统计这条边上的异或值。
这里用到异或的一个性质x xor y xor y=x,考虑以子树的根(不一定是重心)dfs下去找到根的xor前缀和
统计每个点的xor,那么就把01塞到桶里面就行了。
注意这个时候由于每一条路径一定过重心所以先把重心加入,其他的前缀和先xor一个重心,这样可以把重心的影响减去。
尤其注意先找这个点和其他点之间xor值然后再更新桶里面的值。
重心打标及时啊!一塞入就打标。
一开始先找重心可以快一点。。。
具体的可以看我的点分治blog例题1:https://www.cnblogs.com/ljc20020730/p/10347198.html
- # include <bits/stdc++.h>
- # define LL long long
- # define fp(i,s,t) for (int i=s;i<=t;i++)
- using namespace std;
- const int N=1e5+;
- const int MAXBIT=;
- bool used[N];
- int size[N],val[N],cnt[][MAXBIT],n;
- struct rec{int pre,to;}a[*N];
- int tot,head[N];
- template <typename T>inline void read(T& t)
- {
- char c=getchar();t=;
- while(c<''||c>'')c=getchar();
- while(c>=''&&c<='')t=(t<<)+(t<<)+(c^),c=getchar();
- }
- template <typename T,typename... Args> inline void read(T& t, Args&... args)
- {
- read(t);read(args...);
- }
- void write(LL x)
- {
- if (x>) write(x/);
- putchar(''+x%);
- }
- void writeln(LL x)
- {
- write(x);putchar('\n');
- }
- void adde(int u,int v)
- {
- a[++tot].pre=head[u];
- a[tot].to=v;
- head[u]=tot;
- }
- int Get_Root(int u,int fath,int S)
- {
- int pos=;
- for (int i=head[u];i;i=a[i].pre) {
- int v=a[i].to;
- if (v==fath||used[v]) continue;
- if (size[v]>size[pos]) pos=v;
- }
- if (pos!=&&size[pos]>=S/) return Get_Root(pos,u,S);
- return u;
- }
- void Get_Dist(int u,int fath,int num)
- {
- num^=val[u]; size[u]=;
- fp(i,,MAXBIT-)
- cnt[(num & (<<i))>][i]++;
- for (int i=head[u];i;i=a[i].pre){
- int v=a[i].to;
- if (v==fath||used[v]) continue;
- Get_Dist(v,u,num);
- size[u]+=size[v];
- }
- }
- LL ans=;
- void Get_Ans(int u,int fath,int num)
- {
- num^=val[u];
- fp(i,,MAXBIT-)
- ans+=(LL) (<<i)*cnt[(num & (<<i))==][i];
- for (int i=head[u];i;i=a[i].pre){
- int v=a[i].to;
- if (v==fath||used[v]) continue;
- Get_Ans(v,u,num);
- }
- }
- void solve(int u,int fath)
- {
- int root=Get_Root(u,fath,size[u]);
- used[root]=;
- memset(cnt,,sizeof(cnt));
- fp(i,,MAXBIT-)
- cnt[(val[root] & (<<i))>][i]++;
- ans+=(LL)val[root];
- for (int i=head[root];i;i=a[i].pre) {
- int v=a[i].to;
- if (used[v]) continue;
- Get_Ans(v,,);
- Get_Dist(v,,val[root]);
- }
- for (int i=head[root];i;i=a[i].pre) {
- int v=a[i].to;
- if (used[v]) continue;
- solve(v,u);
- }
- }
- int main()
- {
- read(n); fp(i,,n) read(val[i]);
- int u,v;
- fp(i,,n-)
- read(u,v),adde(u,v),adde(v,u);
- int rt=Get_Root(,,n);
- Get_Dist(rt,,); solve(rt,);
- writeln(ans);
- return ;
- }
Problem4 Maja
数据加强的三个点其实就是把大多数标程卡掉的点。
就是K不是偶数而是奇数的时候显然是不存在合法的一条路径的。
这点原题中没有说需要判断。(但是神奇的是没有卡WTF)
这道题显然K这么大不是搜索而是DP,
搜索的复杂度O(4K)太大了吧!!! 而且每个点不止重复走1次。
考虑一条性质:假设从原点(A,B)走到(i,j)恰好走了K/2步然后必然会选择走回去是最优的吧。
这个显然。
然后考虑全局的最优,答案一定是一个循环组成的,就是不停地在某一条路上来回走。
这个也是显然的吧。
那么有余数怎么办?可以证明贪心的选取中点四周的一个Ci,j最大的来回走完余数就是这个点最优的。
这个可以反证? 简单yy一下如果不这样选取那么你还不如走到你最终的中点继续循环呢!
然后就是一个DP+贪心的神仙题目了。
先K/=2,只考虑去,回来其实近似乘以2就行。(其实并不是乘以2)
设f[i][j][r]指的是从(A,B)走到(i,j)经过(i,j)有r次的最优解,那么显然是从四个方向走来的吧。
转移是f[i][j][r]=Max{f[x][y][r-1]}+c[i][j](x,y指的是(i,j)四个相邻点)
回去就是f[i][j][r]+Max{f[x][y][r-1]},那是Ci,j少记一次。
然后剩余的步数(只记去,此时K已经除以2)就是K-r,余数走的步数就是
(K-r)*(Max{c[x][y]}+c[i][j])
然后每次到(i,j)r次计算一下答案。
那个r一维可以滚存,r的取值范围是[0,Min(k,n*m)]
Code:
- # include<bits/stdc++.h>
- # define fp(i,s,t) for (int i=s;i<=t;i++)
- # define inf (0x7f7f7f7f7fll)
- # define int long long
- using namespace std;
- const int N=;
- int f[N][N][],c[N][N];
- int n,m,A,B,K,ans;
- int Get_Max(int a,int b,int c,int d)
- {
- if (b>a) a=b;
- if (c>a) a=c;
- if (d>a) a=d;
- return a;
- }
- template <typename T>inline void read(T& t)
- {
- char c=getchar();t=;
- while(c<''||c>'')c=getchar();
- while(c>=''&&c<='')t=(t<<)+(t<<)+(c^),c=getchar();
- }
- template <typename T,typename... Args> inline void read(T& t, Args&... args)
- {
- read(t);read(args...);
- }
- void write(int x)
- {
- if (x>) write(x/);
- putchar(''+x%);
- }
- void writeln(int x)
- {
- write(x);putchar('\n');
- }
- signed main()
- {
- read(n,m,A,B,K);
- if (K&) { puts("");exit();}
- K=K>>;
- fp(i,,n+) fp(j,,m+)
- c[i][j]=f[i][j][]=f[i][j][]=-inf;
- fp(i,,n) fp(j,,m) read(c[i][j]);
- f[A][B][]=; ans=-inf;
- fp (r,,min(K,n*m)) {
- int now=r&;
- int pst=now^;
- fp(i,,n) fp(j,,m) {
- int temp=Get_Max(f[i-][j][pst],f[i+][j][pst],f[i][j-][pst],f[i][j+][pst]);
- f[i][j][now]=max(temp+c[i][j],-inf);
- if (f[i][j][now]<) continue;
- int Whole_Dist=f[i][j][now]+temp;
- Whole_Dist+=(K-r)*(c[i][j]+Get_Max(c[i-][j],c[i+][j],c[i][j-],c[i][j+]));
- ans=max(ans,Whole_Dist);
- }
- }
- writeln(ans);
- return ;
- }
Problem5 Sunčanje
一道暴力的神仙T5,一看到数据范围就不想暴力的。
但是算算暴力的期望还是值得的。
先按照矩形右下角的x坐标排序,然后枚举每一个长方形,i,看看前面的长方形j是不是包含在i里面的,
被包含的必要条件是a[i].x-a[i].len<a[j].x对吧,不满足必要条件的那么前面也不满足必要条件,直接跳掉。
然后花四个图看看判包含。
- (a[i].y>a[j].y&&a[i].y<a[j].y+a[j].wid)
- ||(a[i].y+a[i].wid>a[j].y&&a[i].y+a[i].wid<a[j].y+a[j].wid)
- ||(a[j].y>a[i].y&&a[j].y<a[i].y+a[i].wid)
- ||(a[j].y+a[j].wid>a[i].y&&a[j].y+a[j].wid<a[i].y+a[i].wid)
更新的时候注意看看谁在谁的下面(一定是初始标号小的放在下面!)
然后瞎加点优化就可以用pascal过4000ms时限了(而C++不行)
然后我就把第19个点的时限改成了6000ms,于是pascal和C++都过了
如果C++代码在XOJ上过不了的话那么加一行
# pragma G++ optimize(3)
Code C++
- # pragma G++ optimize(3)
# include <bits/stdc++.h>- # define fp(i,s,t) for (int i=s;i<=t;i++)
- using namespace std;
- const int N=1e5+;
- struct rec{
- int x,y,len,wid,id;
- }a[N];
- int n;
- bool ans[N];
- inline int read()
- {
- int X=,w=; char c=;
- while(c<''||c>'') {w|=c=='-';c=getchar();}
- while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
- return w?-X:X;
- }
- inline void qsort(int l,int r)
- {
- if (l==r) return;
- int t=rand()%(r-l)+l;
- swap(a[t],a[l]);
- rec v=a[l]; int i=l,j=r;
- while (i<j) {
- while (i<j&&a[j].x>v.x) j--;
- if (i<j) {a[i]=a[j];i++;} else break;
- while (i<j&&a[i].x<v.x) i++;
- if (i<j) {a[j]=a[i];j--;} else break;
- }
- a[i]=v;
- if (l<j) qsort(l,j-);
- if (i<r) qsort(i+,r);
- }
- signed main()
- {
- srand(time(NULL)*);
- n=read();
- fp(i,,n) {
- a[i].x=read();a[i].y=read();a[i].len=read();a[i].wid=read();
- a[i].x+=a[i].len;
- a[i].id=i;
- }
- qsort(,n);
- fp(i,,n) {
- int j=i-;
- while (j>=&&(a[i].x-a[i].len<a[j].x)) {
- if ((a[i].y>a[j].y&&a[i].y<a[j].y+a[j].wid)
- ||(a[i].y+a[i].wid>a[j].y&&a[i].y+a[i].wid<a[j].y+a[j].wid)
- ||(a[j].y>a[i].y&&a[j].y<a[i].y+a[i].wid)
- ||(a[j].y+a[j].wid>a[i].y&&a[j].y+a[j].wid<a[i].y+a[i].wid))
- {
- if (a[i].id<a[j].id) ans[a[i].id]=;
- else ans[a[j].id]=;
- }
- j--;
- }
- }
- fp(i,,n)
- if (ans[i]) putchar('N'),putchar('E'),putchar('\n');
- else putchar('D'),putchar('A'),putchar('\n');
- return ;
- }
Code Pascal
- VAR
- n,i,j:int64; x,y,len,wid,poza,raspuns:array[..] of int64;
- function Poz(a1,b1 : int64) : int64;
- VAR aux,piv:int64;
- Begin
- piv:=x[a1];
- while (a1 < b1) do
- Begin
- if (x[a1] > x[b1]) then Begin
- aux:=x[a1]; x[a1]:=x[b1]; x[b1]:=aux;
- aux:=y[a1]; y[a1]:=y[b1]; y[b1]:=aux;
- aux:=len[a1]; len[a1]:=len[b1]; len[b1]:=aux;
- aux:=wid[a1]; wid[a1]:=wid[b1]; wid[b1]:=aux;
- aux:=poza[a1]; poza[a1]:=poza[b1]; poza[b1]:=aux; end;
- if (piv = x[a1]) then b1:=b1 - else a1:=a1 + ;
- end;
- Poz:=a1;
- end;
- procedure Quick(a1,b1 : int64);
- VAR k:int64;
- Begin
- if (a1 < b1) then
- Begin
- k:=Poz(a1,b1);
- Quick(a1,k - );
- Quick(k + ,b1);
- end;
- end;
- Begin
- Readln(n);
- for i:= to n do
- Begin
- Readln(x[i],y[i],len[i],wid[i]);
- x[i]:=x[i] + len[i];
- poza[i]:=i;
- end;
- Quick(,n);
- raspuns[]:=;
- for i:= to n do
- Begin
- j:=i - ;
- while (j > ) and (x[i] - len[i] < x[j]) do
- Begin
- if (((y[i] > y[j]) and (y[i] < y[j] + wid[j]))
- or ((y[i] + wid[i] > y[j]) and (y[i] + wid[i] < y[j] + wid[j])))
- or (((y[j] > y[i]) and (y[j] < y[i] + wid[i]))
- or ((y[j] + wid[j] > y[i]) and (y[j] + wid[j] < y[i] + wid[i]))) then
- Begin
- if (poza[i] < poza[j]) then raspuns[poza[i]]:= else raspuns[poza[j]]:=;
- end;
- j:=j - ;
- end;
- end;
- for i:= to n do
- if (raspuns[i] = ) then Writeln('NE') else Writeln('DA');
- END.
COCI 2018/2019 CONTEST #2 Solution的更多相关文章
- COCI 2018/2019 CONTEST #2 T4 Maja T5Sunčanje Solution
COCI 2018/2019 CONTEST #2 T4 T5 Solution abstract 花式暴力 #2 T5 Sunčanje 题意 按顺序给你1e5个长方形(左下角坐标&& ...
- 20172328 2018—2019《Java软件结构与数据结构》第二周学习总结
20172328 2018-2019<Java软件结构与数据结构>第二周学习总结 概述 Generalization 本周学习了第三章集合概述--栈和第四章链式结构--栈.主要讨论了集合以 ...
- 2018 - 2019 CTU Open Contest E. Locker Room 【后缀数组】
任意门:http://codeforces.com/gym/101954/problem/E E. Locker Room time limit per test 2.0 s memory limit ...
- 2018 - 2019 CTU Open Contest H. Split Game 【SG函数】
H. Split Game time limit per test 1.0 s memory limit per test 256 MB input standard input output sta ...
- 2018 Multi-University Training Contest 1 Solution
A - Maximum Multiple 题意:给出一个n 找x, y, z 使得$n = x + y +z$ 并且 $n \equiv 0 \pmod x, n \equiv 0 \pmod y, ...
- 2018 Multi-University Training Contest 2 Solution
A - Absolute 留坑. B - Counting Permutations 留坑. C - Cover 留坑. D - Game puts("Yes") #include ...
- 2018 Multi-University Training Contest 3 Solution
A - Problem A. Ascending Rating 题意:给出n个数,给出区间长度m.对于每个区间,初始值的max为0,cnt为0.遇到一个a[i] > ans, 更新ans并且cn ...
- 2018 Multi-University Training Contest 4 Solution
A - Problem A. Integers Exhibition 留坑. B - Problem B. Harvest of Apples 题意:计算$\sum_{i = 0}^{i = m}C( ...
- 2018 Multi-University Training Contest 5 Solution
A - Always Online Unsolved. B - Beautiful Now Solved. 题意: 给出一个n, k 每次可以将n这个数字上的某两位交换,最多交换k次,求交换后的最大 ...
随机推荐
- 解决eth0网卡无法自动加载的问题
问题:输入ifup eth0显示无法加载网卡所在的文件 解决办法: vi /etc/rc.d/rc.local 最后一行加入: ifup eth0 然后重启虚拟机即可解决问题. 本文为博主原创文章,未 ...
- 20155202张旭《网络对抗技术》 week1 PC平台逆向破解及Bof基础实践
20155202张旭<网络对抗技术> week1 PC平台逆向破解及Bof基础实践 1.实践目标: 实践对象:一个名为pwn1的linux可执行文件. 该程序正常执行流程是: main调用 ...
- 20155331《网络对抗》 Exp9 Web安全基础
20155331<网络对抗> Exp9 Web安全基础 实验过程 WebGoat 在终端中输入java -jar webgoat-container-7.0.1-war-exec.jar开 ...
- HTTPUTILS
maven依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId&g ...
- selenium+python自动化----xlrd,xlswriter
1.准备: 使用之前需要先按照:打开cmd,输入pip install xlrd(xlswriter),点击enter; 2.基本使用: xlrd: #打开els文件,参数是文件路径: table = ...
- [T-ARA][Ma boo]
歌词来源:http://music.163.com/#/song?id=22704447 作曲 : 金道勋/Rhymer [作曲 : 金道勋/Rhymer] 作词 : 金道勋 [作词 : 金道勋] 사 ...
- Hexo初体验
title: Hexo初体验 date: 2018-05-10 tags: Hexo categories: Hexo --- Hexo本地安装 Node.js安装 Hexo npm安装如下 npm ...
- PAT甲题题解-1120. Friend Numbers (20)-水题
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789775.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- Python爬虫爬中文却显示Unicode,怎样显示中文--问题解答
首先爬取古诗网站时,显示 原因是因为输出为列表[] 如果写一个循环,输出其中每个元素就为中文了...
- squid介绍和作用
介绍 squid服务程序是一款在Unix系统中最为流行的高性能代理服务软件,通常会被当作网站的前置缓存服务,用于替代用户向网站服务器请求页面数据并进行缓存,通俗来讲,Squid服务程序会接收用户的请求 ...