10.4 代码源 2024 CSP-S 模拟赛 Day 9
省流:\(100+0+0+0=100\)
简称:唐诗
T1
先写了个暴力,然后在想怎么优化,然后想了个区间 DP 但是写的时候又不会了……
然后发现如果这一块数的二进制每一位都有一个数的这一位为 \(0\) 或者都相同,那么这些数合并起来一定最优,然后双指针搞,复杂度 \(O(30n)\)。(这么绕口)
赛后听别人说有规律:
所有数的与的和就是答案要求的数;
然后比一下就行了,复杂度 \(O(n)\)。
想想发现很对,跟我的有异曲同工之妙。
核心代码
fd(k,0,30)
{
f[n+1][k][0]=f[n+1][k][1]=0;
bd(i,n,1)
{
f[i][k][0]=f[i+1][k][0];
f[i][k][1]=f[i+1][k][1];
f[i][k][(a[i].v>>k)&1]++;
}
can[k]=(f[1][k][0]==0||f[1][k][1]==0);
flag&=can[k];
}
int l=n,r=n;
while(l<=r&&l>0)
{
bool fl=1;
fd(k,0,30)
{
if(can[k]) continue;
if(f[l][k][0]-f[r+1][k][0]<=0)
{fl=0;break;}
}
if(l==1)
{
if(fl) ans+=r-l;
else ans+=r-l+1;
break;
}
if(fl) ans+=r-l,r=l-1,--l;
else --l;
}
if(flag) ans=0;
T2
一眼发现一整行/列都一样肯定最后涂的,然后……
二眼暴力,因为 \(n,m\le 1000\),然后懒得写看 T3 了。
\(70\) 分是把一整行/列都一样的直接删掉,然后贪一下就行了。
然后我们发现,设图形中有 \(k\) 列/行完全相同,答案就是 \(n+m-k\)。
为什么呢?
因为最大次数为 \(n+m\),
然后如果有 \(k\) 列/行完全相同的话,就说明对这 \(k\) 行/列的操作无效,所以可以不做这 \(k\) 次操作。
然后可以 Hash 求相同行/列个数,然后对找到的 \(k\) 取个 \(\max\) 就行了。
然后判无解是找类似以下的情况:
...R...B...
...........
...B...R...
核心代码
inline void build(int x,int y,int op)
{
v[x][op].push_back(y);
v[y][op].push_back(x);
}
void dfs(int p,int op,int fa)
{
if(vis[p][op]) {can=0;return;}
vis[p][op]=1;
for(auto i:v[p][op])
{
if(i==fa) continue;
dfs(i,!op,p);
}
vis[p][op]=0;
v[p][op].clear();
}
bool check()
{
id=0;
fd(i,1,n) d1[i]=++id;fd(i,1,m) d2[i]=++id;
fd(i,1,id) v[i][0].clear(),v[i][1].clear();
fd(i,1,n) fd(j,1,m) build(d1[i],d2[j],a[i][j]);
can=1;
fd(i,1,id)
{
dfs(i,0,0);dfs(i,1,0);
if(!can) break;
}
return can;
}
inline int r64()
{
return (rand()^rand())*rand()%mod;
}
inline int H(int x)
{
x^=x<<11,x^=x>>45;
x^=x<<14,x^=x>>19;
return x;
}
void Main()
{
ans=0;
if(!check())
{
cout<<-1<<endl;
return;
}
fd(i,1,n)
{
int hs=st;
fd(j,1,m) hs=H(hs+z[a[i][j]]);
h[i]=hs;
}
sort(h+1,h+n+1);
for(l=1;l<=n;l=r+1)
{
r=l;while(r<n&&h[r+1]==h[l]) ++r;
ans=max(ans,r-l+1);
}
fd(i,1,m)
{
int hs=st;
fd(j,1,n) hs=H(hs+z[a[j][i]]);
h[i]=hs;
}
sort(h+1,h+m+1);
for(l=1;l<=m;l=r+1)
{
r=l;while(r<m&&h[r+1]==h[l]) ++r;
ans=max(ans,r-l+1);
}
ans=n+m-ans;
}
T3
二次省流:\(2n\) 个输入但是
fd(i,1,n)
,唐
赛时怎么调都不过,但是发现一个规律,就是被两个数中间那一段区间完全包含的数不能选,然后想了一个结论但是就过了第一个样例。
正解是按左端点排序+树状数组。
核心代码:
sort(a+1,a+n+1,my);
fd(i,1,n)
{
(f[i]+=ask(a[i].l)+ask(a[i].r)+2)%=mod;
add(a[i].r,f[i]);
(ans+=f[i])%=mod;
}
然后树状数组要开 \(4\) 倍空间……
T4
第一眼只会暴力,但是写 T3 了就没写……
然后好像可以根号分治?
然后正解不是很会……
总结
-
还是审题,输入 \(2n\) 个数但是就读入了 \(n\) 个
-
准备练一下根号分治
-
DP 大法好
\(\LARGE{唐}\)
本文来自博客园,作者:whrwlx,转载请注明原文链接:https://www.cnblogs.com/whrwlx/p/18446582