ARC143

考试情况:一眼订正,鉴定为做出前三题。

A - Three Integers

以前做过 \(n\) 个数的版本,当时还被某人嘲讽说“堆,贪心,这都做不出来?”。

\(3\) 个数就考虑最大数怎么消掉。

如果最大数比其它两个数之和还大,就无解。

否则每次都让最大值减一,使得操作次数为最大值的大小是最优情况。

可以构造很多不同的方案使得最少操作数量为最大值,我的方法是先选择最大值和最小值,将最大值减到中间值的大小,显然最小值够减。然后再将 \(3\) 个数一起减直到最小值为 \(0\),然后将剩下两个相同大小的值一起减到 \(0\)。

代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
long long A,B,C;
long long Sum,Max,Min;
int main()
{
cin>>A>>B>>C;
Sum=A+B+C;
Max=max(max(A,B),C);
if(Max>Sum-Max)
{
puts("-1");
return 0;
}
cout<<Max;
}

B - Counting Grids

题意是说将 \(1\) 到 \(N^2\) 填入一个 \(N \times N\) 的矩阵,要求每个数都满足同一列中存在一个数比自己大同一行中存在一个数比自己小,求方案数。

正难则反,考虑不合法情况。对于一个数字 \(x\),无论它在哪个格子,想让它不合法,就得让它这一列的所有值比 \(x\) 小,它这一行的所有值比 \(x\) 大。

然后对于跟 \(x\) 不在同一行也不在同一列的数字 \(y\),

  • \(y>x\)

    \(y\) 一定大于 \(x\) 所在列 \(y\) 所在行的那一个格子,因为那一个格子比 \(x\) 小。

  • \(y<x\)

    \(y\) 一定小于 \(x\) 所在行 \(y\) 所在列的那一个格子,因为那一个格子比 \(x\) 大。

所以对于任意合法方案,最多只有一个格子不合法。于是只需要枚举不合法的格子的值,然后算方案,答案为 \((N^2)!\) 减去不合法方案数。

对于一个值为 \(x\) 的格子,它所在列的取值范围为 \([1,x-1]\),放置方案数为这里面的数选 \(N-1\) 个的排列数。所在行取值范围为 \([N^2-x+1,N^2]\) ,同理。然后其它 \(N^2-(N-1)-(N-1)+1\) 个值任意放,方案数为其阶乘。把以上三个值乘起来就是当不合法格子为 \(x\) 的方案数。

代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+50,P=998244353;
long long Pow(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b&1)
{
ans=ans*a%P;
}
a=a*a%P;
b>>=1;
}
return ans;
}
long long jc[MAXN];
long long A(long long n,long long m)
{
if(n<m)
return 0;
return jc[n]*Pow(jc[n-m],P-2)%P;
}
long long N;
long long ans;
int main()
{
cin>>N;
jc[0]=1;
for(int i=1;i<=N*N;i++)
jc[i]=jc[i-1]*i%P;
for(int i=1;i<=N*N;i++)
{
ans=(ans+N*N*A(i-1,N-1)%P*A(N*N-i,N-1)%P*jc[N*N-N-N+1]%P)%P;
}
cout<<(jc[N*N]-ans+P)%P;
}

C - Piles of Pebbles

我没看过官方题解,就说我考试的时候的做法。

把 Takahashi 叫做 \(X\),他能取得石头数也叫做 \(X\)。

Aoki 同理。

凭借直觉,最后答案只与 \(A_i \bmod (X+Y)\) 有关。感性理解就是,只要一个地方可以支持 \(X\) 取一次 \(Y\) 再取一次,那么取的这两次就没有意义,对可取性不造成影响。

然后分类讨论:

  • \(X \geq Y\)

    此时 \(Y\) 的能取点大于等于 \(X\) 的能取点。\(Y\) 的策略一定是每次 \(X\) 取了之后,\(Y\) 取 \(X\) 本来能取的点,最后一定是两种情况之一:

    • \(Y\) 取了最后一个 \(X\) 能取的点,\(X\) 没得取了。
    • \(X\) 取了最后一个它能取的点。

    显然 \(X\) 跟 \(Y\) 这样耗是可能会输的,于是 \(X\) 一定会选择一次把所有他能取的所有点全都取完,只要存在一个点 \(Y\) 能取而 \(X\) 不能取,\(Y\) 就赢了,否则 \(X\) 就赢了。

  • \(X < Y\)

    \(Y\) 一定跟 \(X\) 的想法是一样的,而 \(X\) 在能取双方都能取的石头时一定不会取只有自己能取的石头,所以近似看成跟上一种情况,只是结果刚好相反罢了。

代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+50;
int N,X,Y;
int A[MAXN];
int main()
{
cin>>N>>X>>Y;
for(int i=1;i<=N;i++)
{
cin>>A[i];
A[i]=(A[i]%(X+Y));
}
bool flag=false;
if(X>=Y)
{
for(int i=1;i<=N;i++)
if(A[i]<X&&A[i]>=Y)
flag=true;
if(flag)
puts("Second");
else
puts("First");
return 0;
}
for(int i=1;i<=N;i++)
if(A[i]<Y&&A[i]>=X)
flag=true;
if(flag)
puts("First");
else
puts("Second");
return 0;
}

D - Bridges

貌似官方题解还没出。(下午出了)

题目可以理解为一共 \(N\) 个点,把点 \(i\) 拆成 \(2\) 个点,对应点相连。然后给 \(M\) 条边,可以选择 \(A_i\) 连 \(B'_i\),也可以选择 \(A'_i\) 连 \(B_i\),怎样连接才能使图中的桥最少。桥就是边双联通分量里的桥。

可以把这题看做是给一个 \(M\) 条边的无向图,要给这个图定向使得处于强联通分量里的点最多。

不就是造环嘛,跑 dfs,对于树边就向下定向,对于返祖边就向上定向,能成环的重定向之后还是环。环就是强联通分量。

值得注意的是,边可能会重复遇到,其定向以第一次定向为准。若此边已经被定向则不再重定向。

代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+50;
int N,M;
int A[MAXN],B[MAXN];
struct Edge
{
int x,y,Next;
}e[MAXN<<1];
int elast[MAXN],tot=1;
void Add(int x,int y)
{
tot++;
e[tot].x=x;
e[tot].y=y;
e[tot].Next=elast[x];
elast[x]=tot;
}
int ans[MAXN];
bool vis[MAXN];
bool vis2[MAXN];
void dfs(int u)
{
vis2[u]=true;
for(int i=elast[u];i;i=e[i].Next)
{
int v=e[i].y;
if(vis2[v])
{
if(vis[i]==false)
{
vis[i]=vis[i^1]=true;
ans[i]=i&1;
}
}
else
{
ans[i]=i&1;
vis[i]=vis[i^1]=1;
dfs(v);
}
}
}
int main()
{
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
scanf("%d",&A[i]);
}
for(int i=1;i<=M;i++)
{
scanf("%d",&B[i]);
Add(A[i],B[i]);
Add(B[i],A[i]);
}
for(int i=1;i<=N;i++)
{
if(vis2[i]==false)
dfs(i);
}
for(int i=1;i<=M;i++)
{
printf("%d",max(ans[i*2],ans[i*2+1]));
}
}

E - Reversi

官方题解还没出。(下午出了)

其实是一个复合型问题。

设 \(Can_i\) 表示在消除完 \(i\) 的子树的所有点只剩下 \(i\) 时,\(i\) 是不是白色的。

考虑叶子,颜色已经确定了,白色的一定不能变颜色,黑色一定必须变颜色。

考虑儿子全为叶子的点,操作顺序一定是先删除所有白色的,然后如果此节点为黑色,则需要上面支援变为白色,如果此节点为白色,这删除这个节点,将所有黑儿子变白,再将那些变白的儿子删掉。会发现如果没有支援,这个节点的颜色还是确定的。然后它的儿子节点没有变数,可以看做没有。

所以第一部分,可以通过 DP 算出每个点如果没有支援的颜色,然后再考虑这个“强制性支援”。如果儿子是白色的,那一定要支援父亲,如果儿子是黑色的,一定要父亲支援。所以这是一个有向图,每条边代表一个支援关系(必须支援)。

然后拿堆贪心地跑拓扑排序就好了。

如何判无解?拓扑排序的过程中模拟原树的颜色变化(删点改变周围的颜色),如果发现当前删除的点在原树上是当前是黑色的,则说明不合法。

代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+50;
struct Edge
{
int x,y,Next;
}e[MAXN<<1],e1[MAXN];
int elast[MAXN],tot,e1last[MAXN],tot1;
void Add1(int x,int y)
{
tot++;
e[tot].x=x;
e[tot].y=y;
e[tot].Next=elast[x];
elast[x]=tot;
}
bool Use[MAXN];
void Add2(int x,int y)
{
Use[x]=Use[y]=true;
tot1++;
e1[tot1].x=x;
e1[tot1].y=y;
e1[tot1].Next=e1last[x];
e1last[x]=tot1;
}
priority_queue<int,vector<int>,greater<int> >q;
int N;
char Color[MAXN];
int father[MAXN];
bool Can[MAXN];
int Deg[MAXN];
void dfs1(int u,int fa)
{
father[u]=fa;
Can[u]=(Color[u]=='W');
for(int i=elast[u];i;i=e[i].Next)
{
int v=e[i].y;
if(v==fa)
continue;
dfs1(v,u);
if(Can[v]==false)
{
Add2(u,v);
Deg[v]++;
}
else
{
Add2(v,u);
Deg[u]++;
Can[u]^=1;
}
}
}
vector<int>ans;
int main()
{
scanf("%d",&N);
for(int i=1;i<N;i++)
{
int x,y;
scanf("%d%d",&x,&y);
Add1(x,y);
Add1(y,x);
}
scanf("%s",&Color[1]);
dfs1(1,0);
for(int i=1;i<=N;i++)
{
if(Deg[i]==0)
{
q.push(i);
}
}
while(!q.empty())
{
int u=q.top();
q.pop();
if(Color[u]=='B')
{
puts("-1");
return 0;
}
ans.push_back(u);
for(int i=elast[u];i;i=e[i].Next)
{
int v=e[i].y;
if(Color[v]=='W')
Color[v]='B';
else
Color[v]='W';
}
for(int i=e1last[u];i;i=e1[i].Next)
{
int v=e1[i].y;
Deg[v]--;
if(Deg[v]==0)
{
q.push(v);
}
}
}
if(ans.size()!=N)
{
puts("-1");
}
else
{
for(int i=0;i<ans.size();i++)
{
printf("%d ",ans[i]);
}
}
}

F - Counting Subsets

贴一份zjk的做法。暂时没做。









随机推荐

  1. 小编亲身实操,教你配置phpstorm与xdebug的调试配置,不成功你骂我

    开发php,还是找个专业的Ide较好,vscode毕竟在php上不专业,需要下载各种插件才行,还不支持多线程调试,因此小编下载了phpstorm,打算以后用phpstorm来开发php项目,断点调试代 ...

  2. Postman抓包浏览器请求--傻瓜式操作

    1.安装chrome插件(postmanInterceptor插件,在任意插件网站都可搜到,下载安装到浏览器即可),该插件可协助postman捕获https请求 2.安装postman postman ...

  3. 快收藏!最全GO语言实现设计模式

    https://segmentfault.com/a/1190000042859564

  4. Ceres 自动求导解析-从原理到实践

    Ceres 自动求导解析-从原理到实践 目录 Ceres 自动求导解析-从原理到实践 1.0 前言 2.0 Ceres求导简介 3.0 Ceres 自动求导原理 3.1 官方解释 3.2 自我理解 4 ...

  5. .NET中使用Redis总结——2.项目实战

    接上篇.NET中使用Redis总结 -- 1.Redis搭建 看一些Redis相关资料,.NET 方面ServiceStack.Redis 用的比较多,就直接拿来用了. 在使用过程中经常过出现假死状态 ...

  6. 进程,Process模块,join方法,ipc机制,守护进程

    多道技术: """ 在学习并发编程的过程中 不做刻意提醒的情况下 默认一台计算机就一个CPU(只有一个干活的人) """ 单道技术 所有的程 ...

  7. Intellij_idea for循环 快捷键

    for循环四次.用 i 进行for循环 4.for fori 增强for循环 int [] arrays=new int[2]; arrays.for

  8. 靶机渗透【billu_b0x】

    ip扫描 访问80端口 目录扫描 逐个访问 上传一个图片马,结果没有回显 显示file参数为空.请在"文件"参数中提供文件路径 打开发现有用户名 ![] 发现数据库连接的配置信息, ...

  9. 【Java SE】IO流

    1.File类 ①File类的一个对象代表一个文件或一个文件目录 ②File类声明在java.io下 1.1 FIle类的声明 路径分隔符 Windows和DOS系统默认使用'',UNIX和URL使用 ...

  10. 23.04.06_为博客设置https

    title: 为博客设置https协议 categories: - 博客优化 date: 2023-04-06 url_dir: Blog_optimization url_name: setting ...