总之就是 | ZROI CSP联测 Day4
「0.0」序言
因为这个比赛在初赛前一天晚上,当时就没有去打,今天补完之后发现错过了一个上大分的机会(?)
感觉这四个题都还挺水的。
因为没有场上做,于是题目名字就随便来了。
代码的缺省源和之前的博客一样的。
「1.0」踩雷
实际上是扫雷,但是正经人谁扫雷不踩雷啊(?)
「1.1」题目简述
在一个 \(n \times m\) 的地图上,每个点上的数字代表了以这个点为中心的 \(3 \times 3\) 的范围内有几个地雷。
求地图中地雷的总数量。
\(n,m \le 200.\)
「1.2」思路简述
实际上我们只需要找出能够覆盖整张地图的几个点即可,最后的答案就是她们的值之和。
考虑怎么去覆盖整张图。显然 \(n,m\) 都是三的倍数的时候每个点所覆盖的范围都不会浪费。
考虑不被三整除的情况,我们需要从边界上选取一些点来填充未覆盖的点。
「1.3」Code
int n,m,a[201][201],ans;
I int St(int x)
{
if(x%3==1) Heriko Romanno;
else Heriko LjbnHzH;
}
S main()
{
Files();
fr(n),fr(m);
for(int i(1);i<=n;++i)
for(int j(1);j<=m;++j)
fr(a[i][j]);
for(int i(St(n));i<=n;i+=3)
for(int j(St(m));j<=m;j+=3)
ans+=a[i][j];
fw(ans,1);
Heriko Deltana;
}
「2.0」翻转
第一眼感觉特判一下暴力枚举就能过,因为我看错了数据范围(把 \(70\%\) 的 \(n=100\) 看成 \(100\%\) 的了)
「2.1」题目简述
现有一个 \(n \times m\) 的 \(01\) 矩阵,求问将其变为全 \(1\) 矩阵所需的最小代价。
有两种方式可以把一个 \(0\) 变为 \(1\):
-
直接将整个点修改,代价为 \(4.\)
-
设当前点坐标为 \((x,y)\),若有另外一点 \((a,b)\) 为 \(1\) 且 \((a,y),(x,b)\) 均为 \(1\),那么将点 \((x,y)\) 变为 \(1\) 的代价为 \(3.\)
\(n \le 1000.\)
「2.2」思路简述
因为这个题如何改变一个点的颜色已经讲的足够明白了,所以我们就按照这个来即可,即尽量的让代价为 \(3\) 的操作多。
我们将为 \(1\) 的点的行和列相连,最后剩下的没有连通的行和列就用 \(4\) 的代价来变为 \(1\)。
「2.3」Code
CI MXX(1001);
int n,m;
char a[MXX][MXX];
int f[MXX<<1],kcnt,cnt,sz[MXX<<1];
int Find(int x)
{
if(f[x]!=x) f[x]=Find(f[x]);
Heriko f[x];
}
I void Uni(int x,int y)
{
int fx(Find(x)),fy(Find(y));
if(fx!=fy)
{
if(sz[fx]>sz[fy]) swap(fx,fy);
f[fx]=fy;sz[fy]+=sz[fx];--kcnt;
}
}
S main()
{
Files();
fr(n),fr(m);kcnt=n+m;
for(int i(1);i<=n;++i) scanf("%s",a[i]+1);
for(int i(1);i<=(n+m);++i) f[i]=i,sz[i]=1;
for(int i(1);i<=n;++i)
for(int j(1);j<=m;++j)
if(a[i][j]=='1')
Uni(i,j+n),++cnt;
fw(((kcnt-1)<<2)+(n*m-kcnt-cnt+1)*3,1);
Heriko Deltana;
}
「3.0」斜率
不知道有啥感想,没太对这题有感觉。
- 🎨 and 🐏 ON VSCODE LIVE SHARE.
「3.1」题目简述
现在平面上有 \(n\) 个点,求任意两点之间的连线的斜率最接近 \(\frac{p}{q}\) 的值。
\(5 \le n \le 10^6.\)
「3.2」思路简述
既然是让去求斜率了,那么就直球一点。
考虑有一条斜率为 \(\frac{p}{q}\) 的直线在坐标系上平移,我们可以得到所有点按此方向在 \(\frac{p}{q}\) 轴上的投影,不难发现,斜率最接近 \(\frac{p}{q}\) 的两个点的投影一定相邻,这一点简单画图不难发现,于是我们直接按照投影位置进行排序即可。
「3.3」Code
template<typename J>
I J Habs(const J &x) {Heriko x>0?x:-x;}
CI MXX(1e6+1);const double INF(1.14514e9);
LL GCD(int x,int y) {Heriko !y?x:GCD(y,x%y);}
int n,p,q;
double k,res(INF);
struct node
{
LL x,y;
I bool operator < (const node &co) const {Heriko (-x)*p+y*q<(-co.x)*p+co.y*q;}
}
a[MXX],ans;
I double DLT(node ao,node bo) {Heriko ao.x==bo.x?INF:(double)(ao.y-bo.y)/(double)(ao.x-bo.x);}
S main()
{
Files();
fr(n),fr(p),fr(q);
k=(double)p/(double)q;
for(int i(1);i<=n;++i) fr(a[i].x),fr(a[i].y);
sort(a+1,a+1+n);
for(int i(2);i<=n;++i)
{
double now(Habs(DLT(a[i-1],a[i])-k));
if(now<res)
{
res=now;
ans=(node){Habs(a[i-1].x-a[i].x),Habs(a[i-1].y-a[i].y)};
}
}
int G(GCD(ans.y,ans.x));
fw(ans.y/G,0),fw(ans.x/G,1);
Heriko Deltana;
}
「4.0」任务
一个比较水的 DP?
「4.1」题目简述
有 \(n\) 个人和 \(n\) 个任务,如果第 \(i\) 个人被分到 \(i\) 个任务她就会 😫,求有多少分配方式能让至少 \(1\) 个人 😫.
\(n \le 350,mod = 10^9+7\)
「4.2」思路简述
我们设 \(f(i,j)\) 表示前 \(i\) 个人共分得 \(j\) 任务时,至少有一人 😫 的方案数。
那么当第 \(i\) 个人 😫 的时候,剩下的人共分 \(j-i\) 个任务,方案数为 \(C_j^i \times (i-1)^{j-i}.\)
若第 \(i\) 个人不 😫 的时候,即分给它的任务个数 \(k \ne i\) 时,此时方案数为 \(\sum\limits_{k=1}^{n} [k \ne n] C_j^k \times f(i-1,j-k).\)
「4.3」Code
CI MXX(351),MOD(1e9+7);
int n;
LL f[MXX][MXX],c[MXX][MXX];
I void Pre()
{
for(int i(0);i<=n;++i) c[i][0]=c[i][i]=1;
for(int i(1);i<=n;++i)
for(int j(1);j<i;++j)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;
}
LL FstPow(LL x,LL y)
{
LL res(1);
while(y)
{
if(y&1) (res*=x)%=MOD;
(x*=x)%=MOD;y>>=1;
}
Heriko res%MOD;
}
S main()
{
Files();
fr(n);Pre();
for(int i(1);i<=n;++i)
for(int j(0);j<=n;++j)
{
if(j>=i) f[i][j]=FstPow(i-1,j-i)*c[j][i]%MOD;
for(int k(0);k<=j;++k)
if(k==i) continue;
else (f[i][j]+=f[i-1][j-k]*c[j][k]+MOD)%=MOD;
}
fw(f[n][n],1);
Heriko Deltana;
}
「5.0」尾声
这篇严格来说不是在我本地编辑的(?)
实际上是 🐟 在它电脑上开了 VSCODE LIVE SHARE,我和 🐏 加入,实际上东西都是在 🐟 本地的(
上面和 🐏 的对话也是我在编辑的时候 🐏 过来在这个 .md
文件里敲的,所以这是我写的第一个多人合作题解(?)
彩蛋:
/*-------- How An Oier During his day -------·
· First, Fucking Code Everyday!😫
· Second, F**king Code Everyday!😩
· Third, Happy Code Everyday!😀
· Then, Debug Everyday!😅
· Finally, WA TLE MLE RE UKE Everyday!🤬🤮
--------------------------------------------*/