A. 玉兔祥云
$\tt{J\textcolor{red}{Yawa}}$
$\tt{J\textcolor{red}{Yawa}}$
$\tt{J\textcolor{red}{Yawa}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
Sol
对于第一问,考虑抽屉原理。
对于第二问,考虑贪心。
Code
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, y;
cin >> x >> y;
cout << max(0LL, y - 9LL * x)
<< ' ' << y / 10 << endl;
return 0;
}
B. 视界巡航
$\tt{z\textcolor{red}{js123}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{z\textcolor{red}{js123}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{B\textcolor{red}{yGones}\ and\ \tt{c\textcolor{red}{hufuzhe}}}$
Sol
阅读题意可知,这题我们需要动态维护序列的最大值最小值。
每次操作进行修改最大最小并重排的复杂度是错误的,达到了 $\mathcal O(q\times n \log n)$ 的级别。
那么,我们不难想到 C++ 的 STL,multiset。
multiset 与 set 的区别在与,multiset 的元素是可以重复的。根据题意及样例,这里可能会有重复元素出现。
下面介绍一下 multiset:
- multiset 位于
set
库中。请使用#include<set>
等或使用包含set
库的库。 multiset<type>mst
建立一个 type 类型的 multiset 容器。type 可以是int/long long/pair<int,int>/string
等。mst.clear()
清空。mst.insert(x)
向集合插入元素 $x$。mst.empty()
查询集合是否为空。mst.begin()/mst.end()
返回集合开头/结尾迭代器。代码中所用的*s.begin()
和*(--s.end())
即为开头与结尾元素。mst.erase(x)
删除迭代器为 $x$ 的元素。
乱搞做法:平衡树。
赛时码不出来怎么办?C++ 拥有强大的 pb_ds 库,可以直接实现。但是在提交的时候请选择开启 O2 优化的语言,因为 pb_ds 在无 O2 下的表现极劣。
Code
/*
Auther: zjs123
Luogu: 754000
QQ: 755328053
*/
#include<bits/stdc++.h>
using namespace std;
int n,t;
int op;
long long x,a,b;
multiset<long long> s;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>x;
for(int i=1;i<=n;i++){
cin>>a;
s.insert(a);
}
cin>>t;
while(t--){
cin>>op>>b;
if(op==1)x=b;
else if(op==2){
s.erase(--s.end());
s.insert(b);
}
else{
s.erase(s.begin());
s.insert(b);
}
cout<<*(--s.end())+x<<"\n";
}
return 0;
}
C. 恶灵群舞
$\tt{z\textcolor{red}{js123}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{z\textcolor{red}{js123}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{B\textcolor{red}{yGones}\ and\ \tt{c\textcolor{red}{hufuzhe}}}$
Sol
阅读完题意,不难联想到搜索。
因为要求出最右下角的答案,所以我们需要先找出所有答案。
考虑进行搜索,用 $z_{i,j}$ 表示走到 $(i,j)$ 的最小代价。因为每个点最多走不到很多次,穿墙的其实很少,所以时间复杂度 $\mathcal O(nm)$。
Code
#include<bits/stdc++.h>
using namespace std;
struct node{
long long x,y;
long long va;
};
long long n,m,a,b;
long long aa[120][120];
long long h[120][120];
pair<long long,long long> vis[120][120];
long long dx[]={1,-1,0,0};
long long dy[]={0,0,1,-1};
void dfs(long long x,long long y){
h[x][y]=1;
for(long long i=0;i<4;i++){
long long tx=x+dx[i];
long long ty=y+dy[i];
if(tx>0&&tx<=n&&ty>0&&ty<=m&&h[tx][ty]==0&&aa[tx][ty]==0)dfs(tx,ty);
}
}
queue<node> q;
long long z[120][120];
long long ans=0x3f3f3f3f3f3f3f3f;
long long xx,yy;
main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>a>>b;
memset(z,0x3f,sizeof z);
for(long long i=1;i<=n;i++){
for(long long j=1;j<=m;j++){
cin>>aa[i][j];
}
}
memset(vis,0x3f,sizeof vis);
dfs(1,1);
q.push(node{1,1,0});
vis[1][1]=make_pair(1,0);
z[1][1]=0;
while(!q.empty()){
long long x=q.front().x;
long long y=q.front().y;
long long va=q.front().va;
q.pop();
for(long long i=0;i<4;i++){
long long tx=x+dx[i];
long long ty=y+dy[i];
if(tx>0&&tx<=n&&ty>0&&ty<=m&&aa[tx][ty]==0&&vis[tx][ty].second>va+a){
vis[tx][ty].second=va+a;
q.push(node{tx,ty,va+a});
z[tx][ty]=min(z[tx][ty],va+a);
}
if(tx>0&&tx<=n&&ty>0&&ty<=m&&aa[tx][ty]==1&&aa[tx+dx[i]][ty+dy[i]]==0&&vis[tx+dx[i]][ty+dy[i]].second>va+b){
tx+=dx[i];
ty+=dy[i];
vis[tx][ty].second=va+b;
q.push(node{tx,ty,va+b});
z[tx][ty]=min(z[tx][ty],va+b);
}
}
}
for(int i=n;i>=1;i--){
for(long long j=m;j>=1;j--){
if(ans>z[i][j]&&h[i][j]==0){
ans=z[i][j];
xx=i;
yy=j;
}
}
}
if(ans==0x3f3f3f3f3f3f3f3f){
cout<<"No";
return 0;
}
cout<<"Yes\n";
cout<<ans<<" ("<<xx<<","<<yy<<")";
return 0;
}
Nothing
D. 狂热派对
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{B\textcolor{red}{yGones}\ and\ \tt{c\textcolor{red}{hufuzhe}}}$
Sol
其实就是中等的模拟。代码只是变量比较长。
造数据才是大模拟!cyx 为了造数据更容易甚至改了题面。但尽管如此数据生成的代码与 std 的长度相差不大。
我们对于每个记录,按照题意描述检查一下,如果过了就打上标记,并计算时间差得到该题的罚分。被 hack 就取消标记。出现非 CE 或 非 WA on 1 就把这题分数按规定减去 $50$。
Code
/*
Auther: cyx2009
Luogu: 516346
QQ: 2176807108
*/
#include <bits/stdc++.h>
using namespace std;
int n, m, k;
string Problem_Name[2520];
struct Submission
{
string Time, Verdict, Problem;
int Minute;
} CYX_Submission[25020], ZJS_Submission[25020];
string Start_Time;
int INT_Start_Time;
long long CYX_Score, ZJS_Score;
int ZJS_WA[2520];
int CYX_WA[2520];
bool ZJS_Hacked[2520];
bool CYX_Hacked[2520];
bool ZJS_AC[2520];
bool CYX_AC[2520];
int ZJS_Problem_Score[2520];
int CYX_Problem_Score[2520];
map<string, int> Name_to_Id;
int Time_String_to_Int(string Time)
{
int HH, MM, Minute;
HH = (Time[0] - '0') * 10 + (Time[1] - '0');
MM = (Time[3] - '0') * 10 + (Time[4] - '0');
Minute = HH * 60 + MM;
return Minute;
}
int Get_Int_Submission_Time(string Time)
{
int Minute = Time_String_to_Int(Time);
return Minute < INT_Start_Time ? Minute + 24 * 60 - INT_Start_Time : Minute - INT_Start_Time;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= k; i++)
{
cin >> Problem_Name[i];
Name_to_Id[Problem_Name[i]] = i;
}
cin >> Start_Time;
INT_Start_Time = Time_String_to_Int(Start_Time);
for (int i = 1; i <= n; i++)
{
cin >> ZJS_Submission[i].Time >> ZJS_Submission[i].Problem >> ZJS_Submission[i].Verdict;
ZJS_Submission[i].Minute = Get_Int_Submission_Time(ZJS_Submission[i].Time);
}
for (int i = 1; i <= m; i++)
{
cin >> CYX_Submission[i].Time >> CYX_Submission[i].Problem >> CYX_Submission[i].Verdict;
CYX_Submission[i].Minute = Get_Int_Submission_Time(CYX_Submission[i].Time);
}
for (int i = 1; i <= n; i++)
{
if (ZJS_Submission[i].Verdict == "Hacked")
{
if (!ZJS_Hacked[Name_to_Id[ZJS_Submission[i].Problem]])
{
CYX_Score += 100;
ZJS_Hacked[Name_to_Id[ZJS_Submission[i].Problem]] = 1;
ZJS_AC[Name_to_Id[ZJS_Submission[i].Problem]] = 0;
}
}
else if (ZJS_Submission[i].Verdict == "CompileError")
{
continue;
}
else if (ZJS_Submission[i].Verdict.size() >= 23 && ZJS_Submission[i].Verdict.substr(0, 21) == "Wrongansweronpretest(")
{
if (ZJS_Submission[i].Verdict[21] == '1')
continue;
ZJS_WA[Name_to_Id[ZJS_Submission[i].Problem]]++;
}
else if (ZJS_Submission[i].Verdict == "PretestsPassed")
{
ZJS_AC[Name_to_Id[ZJS_Submission[i].Problem]] = 1;
ZJS_Problem_Score[Name_to_Id[ZJS_Submission[i].Problem]] =
max(
Name_to_Id[ZJS_Submission[i].Problem] * 150,
Name_to_Id[ZJS_Submission[i].Problem] * 500 -
ZJS_Submission[i].Minute * Name_to_Id[ZJS_Submission[i].Problem] * 2 -
ZJS_WA[Name_to_Id[ZJS_Submission[i].Problem]] * 50);
ZJS_WA[Name_to_Id[ZJS_Submission[i].Problem]]++;
}
}
for (int i = 1; i <= m; i++)
{
if (CYX_Submission[i].Verdict == "Hacked")
{
if (!CYX_Hacked[Name_to_Id[CYX_Submission[i].Problem]])
{
ZJS_Score += 100;
CYX_Hacked[Name_to_Id[CYX_Submission[i].Problem]] = 1;
CYX_AC[Name_to_Id[CYX_Submission[i].Problem]] = 0;
}
}
else if (CYX_Submission[i].Verdict == "CompileError")
{
continue;
}
else if (CYX_Submission[i].Verdict.size() >= 23 && CYX_Submission[i].Verdict.substr(0, 21) == "Wrongansweronpretest(")
{
if (CYX_Submission[i].Verdict[21] == '1')
continue;
CYX_WA[Name_to_Id[CYX_Submission[i].Problem]]++;
}
else if (CYX_Submission[i].Verdict == "PretestsPassed")
{
CYX_AC[Name_to_Id[CYX_Submission[i].Problem]] = 1;
CYX_Problem_Score[Name_to_Id[CYX_Submission[i].Problem]] =
max(
Name_to_Id[CYX_Submission[i].Problem] * 150,
Name_to_Id[CYX_Submission[i].Problem] * 500 -
CYX_Submission[i].Minute * Name_to_Id[CYX_Submission[i].Problem] * 2 -
CYX_WA[Name_to_Id[CYX_Submission[i].Problem]] * 50);
CYX_WA[Name_to_Id[CYX_Submission[i].Problem]]++;
}
}
for (int i = 1; i <= k; i++)
{
if (ZJS_AC[i])
{
ZJS_Score += ZJS_Problem_Score[i];
}
if (CYX_AC[i])
{
CYX_Score += CYX_Problem_Score[i];
}
}
cout << ZJS_Score << " " << CYX_Score << endl;
if (CYX_Score > ZJS_Score)
{
cout << "cyx" << endl;
}
else if (ZJS_Score > CYX_Score)
{
cout << "zjs" << endl;
}
else
{
cout << "Wow!Same!" << endl;
}
return 0;
}
E. 绿茵战场
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{B\textcolor{red}{yGones}\ and\ \tt{c\textcolor{red}{hufuzhe}}}$
Hint
Sol
之后的分析以及代码均由 $0$ 作为起始下标。
先考虑 Hint 1。
我们发现,$2^{31}-1=2,147,483,647$。
也就是说,$10^9$ 只需要大约 $30$ 个 bit 即可。
我们枚举每个 bit 表示的实际数字并查询。检查返回值与 $cnt$ 的大小关系。
如果返回值比 $cnt$ 小,说明这个 bit 被消除了,也就是原数的这个 bit 是 $1$。
举个例子:$(10)_{10}=(1010)_2$。
$(10-2)_{10}=(8)_{10}=(1000)_2$。
这里我们消去第 $1$ 个 bit,也就是消去了 $2^1=2$。
$f(8)<f(10)$,第 $1$ 个 bit 确实是 $1$。
$(10-1)_{10}=(9)_{10}=(1001)_2$
这里我们消去第 $0$ 个 bit,也就是消去了 $2^0=1$。
$f(9)=f(10)$,第 $0$ 个 bit 不是 $1$。
所以退位什么只会导致 $1$ 个数相同或更多。感兴趣的话可以多找点例子。
综上,我们枚举 $0\sim 29$ 每一个 bit 代表的数 $x$ 并查询。如果得到的结果比 $cnt$ 小,那么 $ans\gets ans+x$,答案加上 $x$。
至此,Hint 1 的解决方法结束。
for(int i=0;i<30;i++)
{
cout<<"? "<<(1<<max(i-1,0))<<'\n';
fflush(stdout);
int c;
cin>>c;
if(c==0)bit++,ans|=1<<i;
if(bit==cnt)break;
}
如何处理 Hint 2 所提到的骗人情况呢?
我们发现题目中给了 $60$ 次的询问限制,而 Hint 1所提到的只有 $30$ 次询问。
我们发现,如果每次 ? 0
$f(n-x)$ 永远不变,一定是 $cnt$。也就是说,一旦返回不是 $1$,也就是不相等,那么一定骗人了。
因此,我们查询 $m$ 次 ? 0
。因为骗人有周期性,所以想知道之后第 $i$ 条询问的回答是否骗人只需查看第 $i\bmod m$ 个询问的结果。
Code
/*
Auther: cyx2009
Luogu: 516346
QQ: 2176807108
*/
#include<bits/stdc++.h>
using namespace std;
bool f[50];//是否说谎
int cnt,m;
int ans,bit;
int main()
{
cin>>cnt>>m;
for(int i=0;i<m;i++)
{
cout<<"? 0\n";
fflush(stdout);
int x;
cin>>x;
if(x!=1)f[i]=0;
else f[i]=1;
}
for(int i=0;i<30;i++)
{
cout<<"? "<<(1<<max(i-1,0))<<'\n';
fflush(stdout);
int c;
cin>>c;
if(!f[i%m])c=(c+1)%3;
if(c==0)bit++,ans|=1<<i;
if(bit==cnt)break;
// cout<<bit<<"\n";
// fflush(stdout);
}
cout<<"! "<<ans<<'\n';
fflush(stdout);
return 0;
}
Nothing
说句闲话,这题是一道大杂烩的原题。
主体部分(Hint 1)为 CF1780D,另一部分(Hint 2)为 CF1010B。
在写下这段的时候,这两题在 CF 的评分均为 *1800,融合之后的这题,个人认为难度放到提高组也是不为过的。
至于为什么出交互,可能是受到了「信息与未来 2022」启发。小学生比赛都能出交互,普及组模拟赛不能出吗?
F. 数码方阵
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{c\textcolor{red}{yx2009}}$
$\tt{J\textcolor{red}{Yawa}}$
Solution
首先,这里输入很奇葩。我们可以把它拆成一个序列,设序列长度为 $N=n\times m$。
假设 $A_{N-1}+2 \leq A_N$。可以证明,Xuan 总是会获胜。
- 如果 Xuan 能够使得 $A_N<A_{N-1}$ 并让 Xiang 面对一个必输的局面,Xuan 就会赢。
- 假设通过使 $a_N<a_{N-1}$ 能够获得所有必胜的局面。然后,如果我们 $a_N \gets a_{N-1}+1$,那么可以从该局面过渡到的所有局面都是必胜的。因此,将 $a_N \gets a_{N-1}+1$ 所得到的局面是必败的。所以,初始局面是必胜的。
接下来,考虑当给定一个满足 $a_N=a_{N-1}+1$ 的局面。根据上述证明,Xuan 和 Xiang 不应该给出最大两个元素差为 $2$ 或更大的局面。综上,我们可以假设 $a$ 的最大两个元素的差为 $1$。
然后,我们发现每一步操作都会将 $\max\{a\}$ 减少 $1$。
当 $\max\{a\}=N-1$ 时,该局面无法进行操作,因此可以根据输入中 $a_N$ 和 $N-1$ 的奇偶性差异来确定赢家。
复杂度为 $O(N)$。
但是输入不是有序,进行排序。复杂度为 $O(N \log N)$。
std 和这里的说法有些不同,std 写法更为简洁。
Code
#include <bits/stdc++.h>
using namespace std;
int n, m;
int a[300020];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n * m; i++)
{
cin >> a[i];
}
sort(a + 1, a + n * m + 1);
for (int i = 1; i <= n * m; i++)
{
a[i] -= i - 1;
}
if (a[n * m] == a[n * m - 1] && (a[n * m] % 2 == 0))
puts("Xiang");
else
puts("Xuan");
return 0;
}
3 条评论
C题,Code 55-56:值改变后依然需要做边界检查。
vis定义成pair意义何在,全程没有使用first
1.虽然但是,对最终结果没有任何影响
2.我tm匆匆忙忙改出来的代码,一个意思知道就行了,空间又不要你付钱
T2:multiset wrong
平衡树 wrong
priorty_queue right