A.移除石子
模拟题。从左上角开始处理,讨论几种情况即可。
复杂度
O
(
T
n
log
n
)
O(Tn\log n)
O ( T n log n ) 。
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
using namespace std;
int T,n,lsh[3005 ],X[3005 ],Y[3005 ],cnt;
deque<int >v[3005 ];
int get (int x) {return lower_bound (lsh+1 ,lsh+1 +cnt,x)-lsh;}
void print (pair<int ,int >x,pair<int ,int >y) {
pair<int ,int >le=make_pair (max (x.fi,y.fi),max (x.se,y.se));int d=max (abs (x.fi-y.fi),abs (x.se-y.se));
cout<<le.fi-d<<' ' <<le.se-d<<' ' <<le.fi<<' ' <<le.se<<"\n" ;
}
int main () {
freopen ("stone.in" ,"r" ,stdin);
freopen ("stone.out" ,"w" ,stdout);
ios::sync_with_stdio (false );
cin.tie (0 ),cout.tie (0 );
cin>>T;
while (T--){
cin>>n,cnt=0 ;for (int i=1 ;i<=n;i++)cin>>X[i]>>Y[i],lsh[++cnt]=X[i];
sort (lsh+1 ,lsh+1 +cnt),cnt=unique (lsh+1 ,lsh+1 +cnt)-lsh-1 ;
for (int i=1 ;i<=cnt;i++)v[i].clear ();for (int i=1 ;i<=n;i++)v[get (X[i])].push_back (Y[i]);
cout<<"Yes" <<"\n" ;
pair<int ,int >fuck=make_pair (0x3f3f3f3f ,0x3f3f3f3f );
for (int i=1 ;i<=cnt;i++){
sort (v[i].begin (),v[i].end ());
while (v[i].size ()>1 ){
int x=v[i][0 ];v[i].pop_front ();
int y=v[i][0 ];v[i].pop_front ();
if (y<fuck.se){
int d=y-x;
cout<<lsh[i]-d<<' ' <<x<<' ' <<lsh[i]<<' ' <<y<<"\n" ;
}
else if (y>fuck.se){
print (fuck,make_pair (lsh[i],x)),fuck=make_pair (0x3f3f3f3f ,0x3f3f3f3f ),v[i].push_front (y);
}
else {
if (lsh[i]-fuck.fi>y-x)print (make_pair (lsh[i],x),make_pair (lsh[i],y));
else if (lsh[i]-fuck.fi<y-x)print (fuck,make_pair (lsh[i],y)),v[i].push_front (x);
else {
cout<<fuck.fi<<".5" <<' ' <<x<<' ' <<lsh[i]<<".5" <<' ' <<y<<"\n" ;
}
}
}
if (v[i].size ()){
if (fuck.fi==0x3f3f3f3f )fuck=make_pair (lsh[i],v[i][0 ]);
else {
print (fuck,make_pair (lsh[i],v[i][0 ])),fuck=make_pair (0x3f3f3f3f ,0x3f3f3f3f );
}
}
}
}
}
B.抓内鬼
这题没想到抽屉原理纯属脑抽
首先把最短路图建出来,如果
1
→
n
1\to n
1 → n 直接相连的话直接把
{
1
,
n
}
\{1,n\}
{ 1 , n } 放到同一组即可。
否则我们假设不存在长度为
3
3
3 的最短路。设直接与
1
1
1 相连的点的集合为
S
S
S ,与
n
n
n 相连的点的集合为
T
T
T ,显然
S
∩
T
=
∅
S\cap T=\empty
S ∩ T = ∅ ,大概是这个样子:
显然只需把
S
S
S 或者
T
T
T 全部分到同一组即可。而根据抽屉原理这是显然成立的。
对于长度为
3
3
3 的最短路,由于
1
,
n
1,n
1 , n 分在了不同组,所以中间这个点总会与
1
1
1 ,
n
n
n 中的一个分在同一组。这样从
S
S
S 到
T
T
T 的任何路径都存在一条边满足两个端点被分在了同一组。
时间复杂度
O
(
n
log
n
)
O(n\log n)
O ( n log n ) 。
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
using namespace std;
int n,m,K,vis[200005 ],vis2[200005 ],a[200005 ],dis[200005 ],res[200005 ];
vector<int >g[200005 ],vec;
priority_queue<pair<int ,int >>q;
struct node {
int u,v;
}e[200005 ];
int main () {
freopen ("catch.in" ,"r" ,stdin);
freopen ("catch.out" ,"w" ,stdout);
ios::sync_with_stdio (false );
cin.tie (0 ),cout.tie (0 );
cin>>n>>m>>K,memset (res,-1 ,sizeof res);
int l=K,r=n-K;
if (K==0 ){for (int i=1 ;i<=n;i++)cout<<"P" ;return 0 ;}
if (K==n){for (int i=1 ;i<=n;i++)cout<<"U" ;return 0 ;}
for (int i=1 ;i<=n;i++)cin>>a[i];
for (int i=1 ;i<=m;i++){
int u,v;cin>>u>>v,g[u].pb (v),g[v].pb (u),e[i]={u,v};
}
memset (dis,0x3f ,sizeof dis),dis[1 ]=0 ,q.push (make_pair (0 ,1 ));
while (q.size ()){
int u=q.top ().se;q.pop ();
if (vis[u])continue ;vis[u]=1 ;
for (auto v:g[u]){
if (dis[u]+a[v]<dis[v])dis[v]=dis[u]+a[v],q.push (make_pair (-dis[v],v));
}
}for (auto u:g[n]){
if (dis[u]+a[n]==dis[n]){
vis2[u]=1 ,vec.pb (u);
}
}vec.pb (n);
if (vis2[1 ]){
if (l>=2 )res[1 ]=res[n]=0 ,l-=2 ;
else if (r>=2 )res[1 ]=res[n]=1 ,r-=2 ;
else {
cout<<"impossible" ;
return 0 ;
}
}
else {
if (l>=vec.size ()){
for (auto x:vec)res[x]=0 ,l--;
res[1 ]=1 ,r--;
}
else if (r>=vec.size ()){
for (auto x:vec)res[x]=1 ,r--;
res[1 ]=0 ,l--;
}
else if (l>=n-vec.size ()){
for (int i=1 ;i<n;i++){
if (!vis2[i])res[i]=0 ,l--;
}res[n]=1 ,r--;
}
else {
for (int i=1 ;i<n;i++){
if (!vis2[i])res[i]=1 ,r--;
}res[n]=0 ,l--;
}
}
for (int i=1 ;i<=n;i++){
if (res[i]==-1 ){
if (l)res[i]=0 ,l--;else res[i]=1 ,r--;
}cout<<(res[i]?"P" :"U" );
}
}
C.异或序列
水题,但是我没看出来
考虑最朴素的状态定义 ,设
d
p
i
dp_i
d p i 表示以
i
i
i 结尾的合法序列数目。那么
d
p
i
=
∑
j
<
i
d
p
j
−
∑
j
<
i
,
p
(
i
)
=
p
(
j
)
d
p
i
⊕
j
dp_{i}=\sum_{j<i}dp_j-\sum_{j<i,p(i)=p(j)}dp_{i\oplus j}
d p i = ∑ j < i d p j − ∑ j < i , p ( i ) = p ( j ) d p i ⊕ j 。其中
p
(
i
)
p(i)
p ( i ) 表示二进制下最高位的
1
1
1 。
不难看出后面的式子可以前缀和优化,时间复杂度
O
(
n
log
n
)
O(n\log n)
O ( n log n ) 。
D.数圈圈
分治好题。之前没遇到过这个想法。
考虑对矩阵分治,每次选择长的一边割开,然后计算跨过
mid
\text{mid}
mid 的圈的数目。
枚举
u
u
u ,
v
v
v ,只需将左右方案数相乘。
记
l
u
l_u
l u 表示向左延伸的最大长度,
d
i
,
u
d_{i,u}
d i , u 表示第
i
i
i 列向下延伸的最大长度。
要求
∑
i
=
max
(
l
u
,
l
v
)
m
i
d
[
d
i
,
u
≥
v
]
\sum_{i=\max(l_u,l_v)}^{mid}[d_{i,u}\ge v]
∑ i = m a x ( l u , l v ) mi d [ d i , u ≥ v ] 。不妨假设
l
u
>
l
v
l_u>l_v
l u > l v (后者再做一遍即可),原式变成了
∑
i
=
l
u
m
i
d
[
d
i
,
u
≥
v
]
\sum_{i=l_u}^{mid}[d_{i,u}\ge v]
∑ i = l u mi d [ d i , u ≥ v ] ,只有
v
v
v 一个变量,用桶维护即可。
单层复杂度
O
(
x
y
+
x
2
)
=
O
(
x
y
)
O(xy+x^2)=O(xy)
O ( x y + x 2 ) = O ( x y ) (
x
≤
y
x\le y
x ≤ y ),即矩形面积。每一层复杂度
O
(
n
m
)
O(nm)
O ( nm ) ,总复杂度
O
(
n
m
(
log
n
+
log
m
)
)
O(nm(\log n+\log m))
O ( nm ( log n + log m )) 。
或许,这就是oi的奇妙之处吧
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
using namespace std;
int n,m;
int up[2005 ][2005 ],down[2005 ][2005 ],le[2005 ][2005 ],ri[2005 ][2005 ],siz[2005 ][2005 ],siz2[2005 ][2005 ],tong[2005 ];
char s[2005 ][2005 ];
ll solve (int X,int X2,int Y,int Y2) {
if (X==X2||Y==Y2)return 0 ;
ll res=0 ;
if (X2-X>Y2-Y){
int mid=X+X2>>1 ;
res+=solve (X,mid,Y,Y2)+solve (mid+1 ,X2,Y,Y2);
for (int i=Y;i<=Y2;i++)for (int j=Y;j<=Y2;j++)siz[i][j]=siz2[i][j]=0 ;
for (int i=Y;i<=Y2;i++){
int l=max (X,up[mid][i]),tot=0 ;
for (int j=i+1 ;j<=Y2;j++)tong[j]=0 ;
for (int j=l;j<=mid;j++)tong[min (Y2,ri[j][i])]++;
for (int j=Y2;j>i;j--){
tot+=tong[j];if (max (X,up[mid][j])<=l)siz[i][j]+=tot;
}
}
for (int i=Y2;i>=Y;i--){
int l=max (X,up[mid][i]),tot=0 ;
for (int j=i-1 ;j>=Y;j--)tong[j]=0 ;
for (int j=l;j<=mid;j++)tong[max (Y,le[j][i])]++;
for (int j=Y;j<i;j++){
tot+=tong[j];if (max (X,up[mid][j])<l)siz[j][i]+=tot;
}
}
for (int i=Y;i<=Y2;i++){
int l=min (X2,down[mid+1 ][i]),tot=0 ;
for (int j=i+1 ;j<=Y2;j++)tong[j]=0 ;
for (int j=mid+1 ;j<=l;j++)tong[min (Y2,ri[j][i])]++;
for (int j=Y2;j>i;j--){
tot+=tong[j];if (min (X2,down[mid+1 ][j])>=l)siz2[i][j]+=tot;
}
}
for (int i=Y2;i>=Y;i--){
int l=min (X2,down[mid+1 ][i]),tot=0 ;
for (int j=i-1 ;j>=Y;j--)tong[j]=0 ;
for (int j=mid+1 ;j<=l;j++)tong[max (Y,le[j][i])]++;
for (int j=Y;j<i;j++){
tot+=tong[j];if (min (X2,down[mid+1 ][j])>l)siz2[j][i]+=tot;
}
}
for (int i=Y;i<=Y2;i++)for (int j=i+1 ;j<=Y2;j++)if (s[mid][i]==s[mid+1 ][i]&&s[mid][j]==s[mid+1 ][j])res+=(ll)siz[i][j]*siz2[i][j];
}
else {
int mid=Y+Y2>>1 ;
res+=solve (X,X2,Y,mid)+solve (X,X2,mid+1 ,Y2);
for (int i=X;i<=X2;i++)for (int j=X;j<=X2;j++)siz[i][j]=siz2[i][j]=0 ;
for (int i=X;i<=X2;i++){
int l=max (Y,le[i][mid]),tot=0 ;
for (int j=i+1 ;j<=X2;j++)tong[j]=0 ;
for (int j=l;j<=mid;j++)tong[min (X2,down[i][j])]++;
for (int j=X2;j>i;j--){
tot+=tong[j];if (max (Y,le[j][mid])<=l)siz[i][j]+=tot;
}
}
for (int i=X2;i>=X;i--){
int l=max (Y,le[i][mid]),tot=0 ;
for (int j=i-1 ;j>=X;j--)tong[j]=0 ;
for (int j=l;j<=mid;j++)tong[max (X,up[i][j])]++;
for (int j=X;j<i;j++){
tot+=tong[j];if (max (Y,le[j][mid])<l)siz[j][i]+=tot;
}
}
for (int i=X;i<=X2;i++){
int l=min (Y2,ri[i][mid+1 ]),tot=0 ;
for (int j=i+1 ;j<=X2;j++)tong[j]=0 ;
for (int j=mid+1 ;j<=l;j++)tong[min (X2,down[i][j])]++;
for (int j=X2;j>i;j--){
tot+=tong[j];if (min (Y2,ri[j][mid+1 ])>=l)siz2[i][j]+=tot;
}
}
for (int i=X2;i>=X;i--){
int l=min (Y2,ri[i][mid+1 ]),tot=0 ;
for (int j=i-1 ;j>=X;j--)tong[j]=0 ;
for (int j=mid+1 ;j<=l;j++)tong[max (X,up[i][j])]++;
for (int j=X;j<i;j++){
tot+=tong[j];if (min (Y2,ri[j][mid+1 ])>l)siz2[j][i]+=tot;
}
}
for (int i=X;i<=X2;i++)for (int j=i+1 ;j<=X2;j++)if (s[i][mid]==s[i][mid+1 ]&&s[j][mid]==s[j][mid+1 ])res+=(ll)siz[i][j]*siz2[i][j];
}
return res;
}
int main () {
freopen ("circle.in" ,"r" ,stdin);
freopen ("circle.out" ,"w" ,stdout);
cin>>n>>m;for (int i=1 ;i<=n;i++)scanf ("%s" ,s[i]+1 );
for (int i=1 ;i<=n;i++){
for (int j=1 ;j<=m;j++){
up[i][j]=(s[i-1 ][j]==s[i][j])?up[i-1 ][j]:i;
le[i][j]=(s[i][j-1 ]==s[i][j])?le[i][j-1 ]:j;
}
}
for (int i=n;i>=1 ;i--){
for (int j=m;j>=1 ;j--){
down[i][j]=(s[i+1 ][j]==s[i][j])?down[i+1 ][j]:i;
ri[i][j]=(s[i][j+1 ]==s[i][j])?ri[i][j+1 ]:j;
}
}
cout<<solve (1 ,n,1 ,m);
}
总结:这次考试完全不在状态,
T
2
T2
T 2 ,
T
3
T3
T 3 都没有观察出来,
T
4
T4
T 4 也反映出知识存在漏洞,看来应该尽快从
csp
\text{csp}
csp 中清醒过来,踏实做题,积累思维。
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」