A. Arithmetic Rectangle

对于一行或者一列的情况可以递推求出最大值。

对于至少一行或者一列的情况,可以定义四个格子一组横向和纵向的相等关系,然后悬线法求最大子矩阵。

时间复杂度$O(nm)$。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=3005;
int Case,n,m,i,j,k,ans,a[N][N],dp[N],f[N],g[N],q[N],t;
inline bool same0(int A,int B,int C,int D){//(i,j) (i+1,j+1)
if(a[A][B]-a[A+1][B]!=a[C][D]-a[C+1][D])return 0;
if(a[A][B+1]-a[A+1][B+1]!=a[C][D+1]-a[C+1][D+1])return 0;
return 1;
}
inline bool same1(int A,int B,int C,int D){//(i,j) (i+1,j+1)
if(a[A][B]-a[A][B+1]!=a[C][D]-a[C][D+1])return 0;
if(a[A+1][B]-a[A+1][B+1]!=a[C+1][D]-a[C+1][D+1])return 0;
return 1;
}
inline void solve(int l,int r){
int i;
q[t=0]=l-1;
for(i=l;i<=r;q[++t]=i++){
while(t&&f[q[t]]>=f[i])t--;
g[i]=q[t];
}
q[t=0]=r+1;
for(i=r;i>=l;q[++t]=i--){
while(t&&f[q[t]]>=f[i])t--;
ans=max(ans,(f[i]+1)*(q[t]-g[i]));
}
}
int main(){
scanf("%d",&Case);
while(Case--){
scanf("%d%d",&n,&m);
ans=min(n,2)*min(m,2);
for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&a[i][j]);
for(i=1;i<=n;i++)for(j=1;j<=m;j++){
dp[j]=1;
if(j>1)dp[j]=2;
if(j>2&&a[i][j-2]-a[i][j-1]==a[i][j-1]-a[i][j])dp[j]=dp[j-1]+1;
ans=max(ans,dp[j]);
}
for(j=1;j<=m;j++)for(i=1;i<=n;i++){
dp[i]=1;
if(i>1)dp[i]=2;
if(i>2&&a[i-2][j]-a[i-1][j]==a[i-1][j]-a[i][j])dp[i]=dp[i-1]+1;
ans=max(ans,dp[i]);
}
n--,m--;
if(n&&m){
for(j=1;j<=m;j++)f[j]=0;
for(i=1;i<=n;i++){
for(j=1;j<=m;j++)if(same0(i,j,i-1,j))f[j]++;else f[j]=1;
for(j=1;j<=m;j=k){
for(k=j;k<=m&&same1(i,j,i,k);k++);
solve(j,k-1);
}
}
}
printf("%d\n",ans);
}
}

  

B. Bytean Road Race

对于每个询问,首先特判显然的情况。

假设要从$x$走到$y$,那么从$x$开始不断朝右下走,碰到分岔则往右走,可以倍增求出离$y$最近的点$R$,同理可以求出碰到分岔往下走时离$y$最近的点$D$。

若$R$或者$D$在$y$右下方,那么显然$x$不能到达$y$,否则它们经过的路线若能围住$y$,则可行。

这意味着$R$再走一步以及$D$再走一步能围住$y$,直接判断即可。

时间复杂度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100010,M=17;
int n,m,q,i,j,x,y,loc[N][2],r[M][N],d[M][N];
inline bool check(int x,int y){
if(loc[x][0]>loc[y][0])return 0;
if(loc[x][1]<loc[y][1])return 0;
int R=x,D=x;
for(int i=M-1;~i;i--){
if(loc[r[i][R]][0]<=loc[y][0]&&loc[r[i][R]][1]>=loc[y][1])R=r[i][R];
if(loc[d[i][D]][0]<=loc[y][0]&&loc[d[i][D]][1]>=loc[y][1])D=d[i][D];
}
if(loc[R][0]>loc[y][0])return 0;
if(loc[R][1]<loc[y][1])return 0;
if(loc[D][0]>loc[y][0])return 0;
if(loc[D][1]<loc[y][1])return 0;
if(loc[R][0]<loc[y][0]&&loc[r[0][R]][0]==loc[R][0])return 0;
if(loc[D][1]>loc[y][1]&&loc[d[0][D]][1]==loc[D][1])return 0;
return 1;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=n;i++)scanf("%d%d",&loc[i][0],&loc[i][1]);
while(m--){
scanf("%d%d",&x,&y);
if(loc[x][0]>loc[y][0])swap(x,y);
if(loc[x][1]<loc[y][1])swap(x,y);
if(loc[x][0]==loc[y][0]){
d[0][x]=y;
if(!r[0][x])r[0][x]=y;
}else{
r[0][x]=y;
if(!d[0][x])d[0][x]=y;
}
}
for(i=1;i<=n;i++){
if(!r[0][i])r[0][i]=n;
if(!d[0][i])d[0][i]=n;
}
for(j=1;j<M;j++)for(i=1;i<=n;i++)d[j][i]=d[j-1][d[j-1][i]],r[j][i]=r[j-1][r[j-1][i]];
while(q--){
scanf("%d%d",&x,&y);
puts(check(x,y)||check(y,x)?"TAK":"NIE");
}
}

  

C. Will It Stop?

只有$2$的幂可行。

#include<cstdio>
long long n;
int main(){
scanf("%lld",&n);
while(n%2==0)n/=2;
puts(n>1?"NIE":"TAK");
}

  

D. Ants

$O(n)$模拟左边的蚂蚁,那么根据树的欧拉遍历总边数可以算出另一只蚂蚁为了走到这个点经过了多少步,继而求出第一次相遇的位置。

可以证明第二次相遇前,右边的蚂蚁一定回不到根,那么算第二次相遇的位置也是同理的。

E. Gophers

线段树线段覆盖,时间复杂度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=500010,M=1222222;
int n,m,q,lim,i,x,y,f[N],tag[M],v[M];
inline void up(int x,int a,int b){
if(tag[x])v[x]=b-a+1;
else if(a==b)v[x]=0;
else v[x]=v[x<<1]+v[x<<1|1];
}
void change(int x,int a,int b,int c,int d,int p){
if(c<=f[a]&&f[b]<=d){
tag[x]+=p;
up(x,a,b);
return;
}
if(a==b)return;
int mid=(a+b)>>1;
if(c<=f[mid])change(x<<1,a,mid,c,d,p);
if(d>=f[mid+1])change(x<<1|1,mid+1,b,c,d,p);
up(x,a,b);
}
int main(){
scanf("%d%d%d%d",&n,&m,&q,&lim);
for(i=2;i<=n;i++)scanf("%d",&f[i]);
while(m--){
scanf("%d",&x);
change(1,1,n,x-lim,x+lim,1);
}
printf("%d\n",v[1]);
while(q--){
scanf("%d%d",&x,&y);
change(1,1,n,x-lim,x+lim,-1);
change(1,1,n,y-lim,y+lim,1);
printf("%d\n",v[1]);
}
}

  

F. Laundry

按天数从大到小贪心选容量最小的颜色,set维护。

#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
typedef pair<int,int>P;
int a[1111111],n,m,i,x,ans;set<P>T;
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=m;i++)scanf("%d",&x),T.insert(P(x,i));
sort(a+1,a+n+1);
for(i=n;i;i--){
x=a[i];
set<P>::iterator it=T.lower_bound(P(x*5,0));
if(it!=T.end()){
ans++;
T.erase(it);
continue;
}
it=T.lower_bound(P(x*3,0));
if(it==T.end())return puts("NIE"),0;
T.erase(it);
ans++;
it=T.lower_bound(P(x*2,0));
if(it==T.end())return puts("NIE"),0;
T.erase(it);
ans++;
}
printf("%d",ans);
}

  

G. Bits Generator

每个$z$向计算一步后的$z'$连边建图,倍增求Hash值判断,时间复杂度$O(m\log n)$。

#include<cstdio>
const int SEED=233,P=1000000007,N=1000010,LIM=17;
int A,C,K,m,n,goal,i,j,ans;
int f[LIM][N],g[LIM][N],pw[LIM];
char a[N];
inline int ask(int x,int m){
int ret=0;
for(int i=0;i<LIM;i++)if(m>>i&1){
ret=(1LL*ret*pw[i]+g[i][x])%P;
x=f[i][x];
}
return ret;
}
int main(){
scanf("%d%d%d%d%d%s",&A,&C,&K,&m,&n,a+1);
for(i=1;i<=n;i++)goal=(1LL*goal*SEED+a[i])%P;
for(i=0;i<m;i++){
int x=(1LL*i*A+C)/K%m;
int y=x<m/2?'0':'1';
f[0][i]=x;
g[0][i]=y;
}
for(pw[0]=SEED,i=1;i<LIM;i++)pw[i]=1LL*pw[i-1]*pw[i-1]%P;
for(j=1;j<LIM;j++)for(i=0;i<m;i++){
f[j][i]=f[j-1][f[j-1][i]];
g[j][i]=(1LL*g[j-1][i]*pw[j-1]+g[j-1][f[j-1][i]])%P;
}
for(i=0;i<m;i++)if(ask(i,n)==goal)ans++;
printf("%d",ans);
}

  

H. Afternoon Tea

在第$i(i<n)$个位置喝饮料可以看成贡献$1-\frac{1}{2^i}$,比较整数和小数部分即可。而小数部分除了$n=1$的情况外可以直接由第$n-1$次操作判断。

#include<cstdio>
int n,i,x,b[2];char a[111111];
int cmp(){
if(b[0]!=b[1])return b[0]>b[1]?-1:1;
if(n==1)return 0;
return a[n-1]=='H'?1:-1;
}
int main(){
scanf("%d%s",&n,a+1);
for(i=1;i<n;i++)b[a[i]=='H'?0:1]++;
int ret=cmp();
if(ret==-1)puts("H");
if(ret==0)puts("HM");
if(ret==1)puts("M");
}

  

I. Intelligence Quotient

建立二分图,每个点向源/汇连边,容量为选他的收益,不认识的人之间连$inf$边求最小割即可。

#include<cstdio>
typedef long long ll;
const int N=810;
const ll inf=1LL<<60;
struct E{int t;ll f;E*nxt,*pair;}*g[N],*d[N],pool[500000],*cur=pool;
int n,m,i,j,k,x,y,S,T,h[N],gap[N],A,B;ll ans;
bool vis[N];
bool f[N][N];
inline void add(int s,int t,ll f){
E*p=cur++;p->t=t;p->f=f;p->nxt=g[s];g[s]=p;
p=cur++;p->t=s;p->f=0;p->nxt=g[t];g[t]=p;
g[s]->pair=g[t];g[t]->pair=g[s];
}
inline ll min(ll a,ll b){return a<b?a:b;}
ll sap(int v,ll flow){
if(v==T)return flow;
ll rec=0;
for(E*p=d[v];p;p=p->nxt)if(h[v]==h[p->t]+1&&p->f){
ll ret=sap(p->t,min(p->f,flow-rec));
p->f-=ret;p->pair->f+=ret;d[v]=p;
if((rec+=ret)==flow)return flow;
}
if(!(--gap[h[v]]))h[S]=T;
gap[++h[v]]++;
d[v]=g[v];
return rec;
}
void dfs(int x){
if(vis[x])return;
vis[x]=1;
for(E*p=g[x];p;p=p->nxt)if(p->f)dfs(p->t);
}
int main(){
scanf("%d%d%d",&n,&m,&k);
S=n+m+1;T=S+1;
while(k--)scanf("%d%d",&x,&y),f[x][y]=1;
for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(!f[i][j])add(i,j+n,inf);
for(i=1;i<=n;i++)scanf("%d",&x),ans+=x,add(S,i,x);
for(i=1;i<=m;i++)scanf("%d",&x),ans+=x,add(i+n,T,x);
for(gap[0]=T,i=1;i<=T;i++)d[i]=g[i];
while(h[S]<T)ans-=sap(S,inf);
printf("%lld\n",ans);
dfs(S);
for(i=1;i<=n;i++)if(vis[i])A++;
printf("%d\n",A);
for(i=1;i<=n;i++)if(vis[i])printf("%d ",i);
puts("");
for(i=1;i<=m;i++)if(!vis[i+n])B++;
printf("%d\n",B);
for(i=1;i<=m;i++)if(!vis[i+n])printf("%d ",i);
puts("");
}

  

J. Cave

枚举每个$k$,那么剩下每个子树大小均为$\frac{n}{k}$,因此$k$一定是$n$的因子,若此时还满足子树大小为它的倍数的点数够$k$个,则可行。

#include<cstdio>
const int N=3000010;
int n,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
int size[N];
int cnt[N];
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int y){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x),size[x]+=size[v[i]];
cnt[size[x]]++;
}
inline bool check(int x){
if(n%x)return 0;
int w=n/x,t=0;
for(int i=w;i<=n;i+=w)t+=cnt[i];
return t==x;
}
int main(){
scanf("%d",&n);
for(i=2;i<=n;i++)x=i,scanf("%d",&y),add(x,y),add(y,x);
dfs(1,0);
for(i=1;i<=n;i++)if(check(i))printf("%d ",i);
}

  

K. Cross Spider

特判共线的情况,得到$3$个不共线的点时叉积求出法向量判断。

#include<cstdio>
typedef long long ll;
struct P{
ll x,y,z;
P(){}
P(ll _x,ll _y,ll _z){x=_x,y=_y,z=_z;}
P operator-(const P&b)const{return P(x-b.x,y-b.y,z-b.z);}
P det(const P&b)const{
return P(y*b.z-z*b.y,
z*b.x-x*b.z,
x*b.y-y*b.x);
}
ll dot(const P&b)const{return x*b.x+y*b.y+z*b.z;}
}A,B,C,F,O;
int cnt,n;
bool dotsInline(const P&A,const P&B,const P&C){
P D=(B-A).det(C-A);
return !D.x&&!D.y&&!D.z;
}
int main(){
scanf("%d",&n);
while(n--){
scanf("%lld%lld%lld",&O.x,&O.y,&O.z);
if(!cnt)A=O,cnt=1;
else if(cnt==1)B=O,cnt=2;
else{
if(dotsInline(A,B,O))continue;
if(cnt==2){
C=O,cnt=3;
F=(B-A).det(C-A);
continue;
}
if(F.dot(O-A))return puts("NIE"),0;
}
}
puts("TAK");
}

  

X Open Cup named after E.V. Pankratiev. European Grand Prix的更多相关文章

  1. XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix

    A. Accommodation Plan 对于已知的$K$个点,离它们距离都不超过$L$的点在树上是一个连通块,考虑在每种方案对应的离$1$最近的点统计. 即对于每个点$x$,统计离它距离不超过$L ...

  2. XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix

    A. Artifacts 建立语法分析树,首先根据上下界判断是否有解,然后将所有数按下界填充,线段树判断是否存在和超过$K$的子区间. B. Brackets and Dots 最优解中一定包含一对中 ...

  3. XVIII Open Cup named after E.V. Pankratiev. Grand Prix of SPb

    A. Base $i - 1$ Notation 两个性质: $2=1100$ $122=0$ 利用这两条性质实现高精度加法即可. 时间复杂度$O(n)$. #include<stdio.h&g ...

  4. XV Open Cup named after E.V. Pankratiev. GP of Tatarstan

    A. Survival Route 留坑. B. Dispersed parentheses $f[i][j][k]$表示长度为$i$,未匹配的左括号数为$j$,最多的未匹配左括号数为$k$的方案数. ...

  5. XVII Open Cup named after E.V. Pankratiev. GP of SPb

    A. Array Factory 将下标按前缀和排序,然后双指针,维护最大的右边界即可. #include<cstdio> #include<algorithm> using ...

  6. XVI Open Cup named after E.V. Pankratiev. GP of Ukraine

    A. Associated Vertices 首先求出SCC然后缩点,第一次求出每个点能到的点集,第二次收集这些点集即可,用bitset加速,时间复杂度$O(\frac{nm}{64})$. #inc ...

  7. XVI Open Cup named after E.V. Pankratiev. GP of Peterhof

    A. (a, b)-Tower 当指数大于模数的时候用欧拉定理递归计算,否则直接暴力计算. #include<cstdio> #include<algorithm> #incl ...

  8. XVI Open Cup named after E.V. Pankratiev. GP of Siberia

    A. Passage 枚举两个点,看看删掉之后剩下的图是否是二分图. #include <bits/stdc++.h> using namespace std ; const int MA ...

  9. XVI Open Cup named after E.V. Pankratiev. GP of Ekaterinburg

    A. Avengers, The 留坑. B. Black Widow 将所有数的所有约数插入set,然后求mex. #include<bits/stdc++.h> using names ...

随机推荐

  1. python 学习地址

    本章主要记录学习python过程中借鉴的一些网站,并感谢这些博主辛勤付出. python官网:https://www.python.org/ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...

  2. 金融量化分析【day110】:NumPy通用函数

    一.通用函数 能同时对数组中所有元素进行运算的函数 1.一元函数 1.sqrt 2.ceil 3.modf 4.isnan 5.abs 2.二元函数 1.maxinum 二.数学和统计方法 1.sum ...

  3. 数据结构Java实现04---树及其相关操作

    首先什么是树结构? 树是一种描述非线性层次关系的数据结构,树是n个数据结点的集合,这些集结点包含一个根节点,根节点下有着互相不交叉的子集合,这些子集合便是根节点的子树. 树的特点 在一个树结构中,有且 ...

  4. SCI,EI,ISTP

    SCI:   Science Citation Index EI:     The Engineering Index ISTP:  Index to Scientific & Technic ...

  5. Javaweb学习笔记——(二十四)——————图书商城项目

    图书商城          环境搭建         1.导入原型             *用户模块             *分类模块             *图书模块              ...

  6. luoguo 1306 斐波那契公约数

    这题难度不大,主要是小结论:斐波那契第n项和第m项公约数就是第gcd(n,m)项 大概能猜出来,毕竟斐波那契数列反过来实在太像计算公约数的步骤了 日后填坑证明吧

  7. ntp 服务:Server dropped: Strata too high

    1.通过ntpdate -d 服务端IP,显示Server dropped: Strata too high vi /etc/ntp.conf 在ntpd服务端的配置中添加 server 127.12 ...

  8. FTP主动及被动模式效果图

  9. jquery.ajax()详解

    jQuery.ajax() 函数详解 traditional 如果你希望使用传统方式来序列化参数,将该属性设为true. 传递数组时, traditional必须为true var arr = []; ...

  10. Python--抽象类接口类

    一. 继承有两种用途: """ 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了 ...