XXII Open Cup , Grand Prix of Poland
链接
A. AMPPZ in the times of disease
题解
考虑如果确定了 个集合中的一个点,那么对于其他点,只需要分给距离最近的点即可。容易证明这是唯一合法的构造方案。
考虑如何确定 个集合中的点。容易发现,如果 ,那么对于任何一个点,离他最远的点一定不在同一个集合中。同样对于任何一个 求出离集合 最近点最远的点,那么这个点也一定不在 中。
复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=2000010;
struct node{
int x,y;
node(int x=0,int y=0):x(x),y(y){}
}p[N];
ll dis2(node a,node b){return 1ll*(a.x-b.x)*(a.x-b.x)+1ll*(a.y-b.y)*(a.y-b.y);}
int a[N];ll d[N];
int main()
{
int T;scanf("%d",&T);
while(T --> 0)
{
int n,k;scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
a[1]=1,d[1]=0;
for(int i=2;i<=n;i++) d[i]=dis2(p[i],p[1]);
for(int i=2;i<=k;i++)
{
int u=0;
for(int j=1;j<=n;j++) if(d[j]>d[u]) u=j;
a[i]=u;
for(int j=1;j<=n;j++) d[j]=min(d[j],dis2(p[j],p[u]));
}
for(int i=1;i<=n;i++)
{
ll dis=1e18;int u=0;
for(int j=1;j<=k;j++) if(dis2(p[i],p[a[j]])<dis) dis=dis2(p[i],p[a[j]]),u=j;
printf("%d ",u);
}
puts("");
for(int i=1;i<=n;i++) d[i]=0;
}
return 0;
}
B. Babushka and her pierogi
咕了
题解
考虑答案的下界,首先交换次数不可能低于 减置换环个数,并且交换极差和不可能低于 。可以证明,存在构造可以达到这个下界。
构造不会。
E. Epidemic
题解
考虑点 表示第 个人在 时间的情况, 向 连一条有向边,表示如果 有可能感染了,那么 也有可能感染了。可以发现,由于应当假设所有不保证是阴性的人都是阳性,所以一个阳性检测除了隔离一个人之外不会导致其他影响。对于一次聚会,把所有 和 之间都连边,表示如果其中一个有可能感染,那么其余也有可能感染。对于一次阴性检测,相当于所有能导致这个点阳性的点都不是阳性,所以它能到达的所有点都是阴性,同时如果一个点不能通过不一定是阴性的点到达某个 ,那么这个点也一定是阴性。
直接处理复杂度是 的。考虑实际上只要对每次聚会的人复制点即可,同时注意到一次聚会得到的复制点是等价的,不妨直接用一个点来代替这个团。这样点数和边数都是 的,用 set 维护非阴性且未被隔离的点集。复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
using namespace std;
const int N=2000010;
int deg[N],id[N],neg[N],tt;vector<int>g[N],h[N];
void add(int u,int v){g[u].push_back(v),h[v].push_back(u),++deg[u];}
set<int>res,pos[N];
void new_node(vector<int> tmp)
{
int u=++tt;
for(int v:tmp)
if(!neg[id[v]]) add(u,id[v]);
else res.insert(v);
for(int v:tmp)
pos[u].insert(v),pos[id[v]].erase(v),id[v]=u;
if(!deg[u])
{
for(int v:tmp) res.erase(v);
neg[u]=true;
}
}
void make_neg(int u)
{
if(neg[u]) return;
neg[u]=true;
for(auto v:pos[u]) if(res.count(v)) res.erase(v);
for(int v:g[u]) make_neg(v);
for(int v:h[u]) if(!neg[v] && !--deg[v]) make_neg(v);
}
int las,n;
int decode(){int x;scanf("%d",&x);return (x-1+las)%n+1;}
int main()
{
int t;
scanf("%d",&t);
for(int _=1;_<=t;_++)
{
int m;scanf("%d%d",&n,&m);
tt=n;
for(int i=1;i<=n;i++) res.insert(i),id[i]=i,pos[i].insert(i);
for(int i=1;i<=m;i++)
{
char op[3];scanf("%s",op);
if(op[0]=='K')
{
int k;scanf("%d",&k);
vector<int>tmp;
for(int j=1,x;j<=k;j++) x=decode(),tmp.push_back(x);
new_node(tmp);
}
else if(op[0]=='N')
{
int x=decode();
make_neg(id[x]);
}
else if(op[0]=='P')
{
int x=decode();
if(id[x]) pos[id[x]].erase(x),res.erase(x),id[x]=0;
}
else
{
int x=decode();
if(res.empty()){puts("TAK"),las=0;continue;}
auto y=res.lower_bound(x);
if(y==res.end()) y=res.begin();
printf("NIE %d\n",las=*y);
}
}
las=0;
for(int i=1;i<=tt;i++) id[i]=0,pos[i].clear(),g[i].clear(),h[i].clear(),neg[i]=false,deg[i]=0;
res.clear();
tt=0;
}
return 0;
}
G. Gebyte’s Grind
题解
考虑把每个位置当成一个函数,容易发现每个函数总是可以被表示成一个三元组 ,若 则为 ,否则若 则为 ,否则为 。
容易发现两个这样的折线复合之后也是这样的折线,用线段树维护折线函数,这样每次询问可以直接线段树上二分解决。
复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2000010;
typedef long long ll;
const ll inf=1e12;
struct node{
ll a,b,c;//if x<=a : 0 . elif x<=b : c . else c+(x-b)
node(ll a=0,ll b=0,ll c=0):a(a),b(b),c(c){}
ll calc(ll x){return x<=a?0:(x<=b?c:c+(x-b));}
};
node operator +(node x,node y)
{
if(x.c<=y.a) return node(y.a-x.c+x.b,y.b-x.c+x.b,y.c);
if(x.c<=y.b) return node(x.a,y.b-x.c+x.b,y.c);
return node(x.a,x.b,x.c-y.b+y.c);
}
node t[N<<2],a[N];
void build(int u,int l,int r)
{
if(l==r){t[u]=a[l];return;}
int mid=(l+r)>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
t[u]=t[u<<1]+t[u<<1|1];
}
void insert(int u,int l,int r,int p,node v)
{
if(l==r){t[u]=v;return;}
int mid=(l+r)>>1;
if(p<=mid) insert(u<<1,l,mid,p,v);
else insert(u<<1|1,mid+1,r,p,v);
t[u]=t[u<<1]+t[u<<1|1];
}
int qry(int u,int l,int r,int p,ll &x)
{
if(l==r)
{
if(t[u].calc(x)==0) return l;
else{x=t[u].calc(x);return l+1;}
}
int mid=(l+r)>>1;
if(p==l)
{
if(t[u<<1].calc(x)==0) return qry(u<<1,l,mid,p,x);
x=t[u<<1].calc(x);
return qry(u<<1|1,mid+1,r,mid+1,x);
}
if(p>mid) return qry(u<<1|1,mid+1,r,p,x);
int v=qry(u<<1,l,mid,p,x);
if(v<=mid) return v;
else return qry(u<<1|1,mid+1,r,mid+1,x);
}
node read()
{
char op[3];ll x;scanf("%s%lld",op,&x);
if(op[0]=='B') return node(x,x,0);
if(op[0]=='K') return node(x-1,inf,x);
return node(0,x,x);
}
int main()
{
int T;
scanf("%d",&T);
while(T --> 0)
{
int n,m;ll X;scanf("%d%d%lld",&n,&m,&X);
for(int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
while(m --> 0)
{
char op[3];int p;scanf("%s%d",op,&p);
if(op[0]=='Z') insert(1,1,n,p,read());
else
{
ll x=X;
int v=qry(1,1,n,p,x);
if(v<=p) puts("-1");
else printf("%d\n",v-1);
}
}
}
return 0;
}
I. Interesting Numbers
题解
和这题做法几乎一致。考虑建 Trie 树,然后设 表示当前递归到 的子树和 的子树。对于每个位置,如果当前限制位为 ,那么转移到 ,如果限制位为 转移到 ,再和 各自子树大小取 。 时特判, 或 时特判掉。
复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=30010,D=20;
int ch[N*D][2],siz[N*D],tt=1;
void insert(int x)
{
int u=1;
for(int i=D-1;i>=0;siz[u]++,u=ch[u][x>>i&1],i--) if(!ch[u][x>>i&1]) ch[u][x>>i&1]=++tt;
siz[u]++;
}
int qry(int a,int b,int x,int d=D-1)
{
if(d==-1) return max(siz[a],siz[b]);
if(!a) return siz[b];if(!b) return siz[a];
if(a==b)
{
if(x>>d&1) return qry(ch[a][0],ch[a][1],x,d-1);
else return max(qry(ch[a][0],ch[a][0],x,d-1),qry(ch[a][1],ch[a][1],x,d-1));
}
if(x>>d&1) return qry(ch[a][0],ch[b][1],x,d-1)+qry(ch[a][1],ch[b][0],x,d-1);
else return max({qry(ch[a][0],ch[b][0],x,d-1),qry(ch[a][1],ch[b][1],x,d-1),siz[a],siz[b]});
}
int main()
{
int t;
scanf("%d",&t);
while(t --> 0)
{
int n,x;scanf("%d%d",&n,&x),++x;
for(int i=1,x;i<=n;i++) scanf("%d",&x),insert(x);
printf("%d\n",qry(1,1,x));
for(int i=1;i<=tt;i++) ch[i][0]=ch[i][1]=siz[i]=0;
tt=1;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理