ZhouChuang Coding CSP-J 仿真模拟 题解
ZhouChuang Coding CSP-J 仿真模拟 题解
T1 Retribution ∼ Cycle of Redemption ∼
按照题意模拟即可。可以采用递推减少代码编写难度。
注意不开long long的话会获得 60 分的高分。
这里涉及到一个知识点,int类型最多支持算到12!,而long long 最多支持算到20!也就是刚好题目的数据范围,而我们通过简单估算可以发现20!*2仍然在long long的数据范围内所以不用写高精度。
::::info[AC code]
#include<bits/stdc++.h>
using namespace std;
const int maxn=21;
typedef long long ll;
int a[maxn];
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
a[0]=1;
for(int i=1;i<=n;i++)
a[i]=a[i-1]*i;
cout<<(a[n]-n)*2<<" "<<(a[n]-2*n)*2<<" "<<2<<endl;
return 0;
}
::::
T2 Givemeygg lose his unique coin
首先此题旨在考查阅读理解能力。
翻译过来就是一个无向图,每条边有边权,删去一些边使得这个图变成一个二分图,使得花费价值最少。
然后可以发现这个题的
不过也需要注意到这个题的边权是
不开long long 会获得 80 分的高分。 ::::info[AC Code]
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
typedef long long ll;
int a[maxn],b[maxn],c[maxn];
ll k[maxn],num=10000000000;
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>a[i]>>b[i]>>k[i];
for(int i=0;i<=(1<<n)-1;i++)
{
int x=i,tot=1;
memset(c,0,sizeof(c));
while(x)
c[tot++]=x%2,x/=2;
ll ans=0;
for(int j=1;j<=m;j++)
if(c[a[j]]==c[b[j]])
ans+=k[j];
num=min(num,ans);
}
cout<<num<<endl;
return 0;
}
::::
T3 Alice vs Bob Ⅰ
考虑 DP 求解。
记状态
具体的,如果
同样的,如果
然后就可以 DP递推 或者 记忆化搜搜求解了。时间复杂度
如果想要进一步优化,可以发现上面两种转移本质上都一模一样,考虑把 A / B 必胜的意义改成先手/后手必胜,那么两部分的转移就可以完全统一到一起,也就是 std 的写法。
最后有一个小细节,注意题目中开头的冷笑话写的是Alice 中的 ice 化掉了,因此我们应该输出 Al 而不是谐音的 AI 。(注意前一个是L的小写后一个是i的大写)
::::info[AC Code]
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
vector<int>e[maxn];
int pos[maxn][20],t,n,m,k;
void upd(int x,int k)
{
for(int i=0;i<e[x].size();i++)
if(pos[e[x][i]][k-1]==2)
{
pos[x][k]=1;
return;
}
pos[x][k]=2;
return;
}
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n>>m>>k;
string s;
cin>>s;
for(int i=1;i<=n;i++)
e[i].clear();
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
e[x].push_back(y);
}
for(int i=1;i<=n;i++)
if(s[i-1]=='A')
pos[i][0]=1;
else
pos[i][0]=2;
for(int i=1;i<=2*k;i++)
for(int x=1;x<=n;x++)
upd(x,i);
if(pos[1][2*k]==1)
cout<<"Al"<<endl;
else
cout<<"Bob"<<endl;
}
return 0;
}
::::
T4 完蛋了这么简单的题目放T4肯定被切穿了吧
如题,结论题。
第一步翻译题目意思。
有
定义环中只剩一枚硬币时它的左边与右边都是自己。
首先可以发现,对于连续一段状态相同的硬币,其中必定有且只有一个硬币对答案有贡献,也就是一直取一直取取到这一段只剩一个硬币,且两端都异面,此时再取这个硬币才会对答案有贡献。于是这部分考虑贪心求最大。
于是这个时候我们的硬币形如
首先显然可以发现,这
于是来到了本题最为诈骗的地方,我们考虑证明对于取环中任意
如下:
于是代码实现就很简单了,我们先对原来的环断环为链,然后去重,然后对于新序列排序,取最大的
注意不要忘记对状态全部相等的情况特判,这个时候答案为
总复杂度
::::info[AC Code]
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
typedef long long ll;
int vis[maxn<<1];
ll a[maxn<<1],b[maxn];
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>vis[i];
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
vis[i+n]=vis[i],a[i+n]=a[i];
int pos=1;
while(vis[pos]==vis[pos+1]&&pos<n)
pos++;
if(pos==n)
{
cout<<0<<endl;
return 0;
}
if(pos!=n)
pos++;
else
pos=1;
ll mx=a[pos],num=0,ans=0;
for(int i=pos;i<pos+n;i++)
if(vis[i]!=vis[i+1]||i==pos+n-1)
b[++num]=mx,mx=a[i+1];
else
mx=max(mx,a[i+1]);
sort(b+1,b+1+num);
for(int i=num/2+1;i<=num;i++)
ans+=b[i];
cout<<ans<<endl;
return 0;
}
:::: T5 Alice vs Bob Ⅱ
决策构造的结论题。由于我们要将这颗树标记合法的边,我们可以想一下这个游戏的性质。
- 1.首先可以发现一个简单的结论,不可能有两个相邻的节点使得它们都为
1 。
很容易发现,因为如果有一个节点为
- 2.其次,两个相邻节点都为
2 是可能的。
因为两个后手必胜的路径可能有所不同,当两个路径不经过同一个点时就可以存在两个相邻的
- 3.当一个节点没有出边时,它必定为
1 。
自己手玩可知。
通过上面三条结论我们可以发现一个简单的构造方法:当一个点为
然后考虑怎么将询问次数再次降低,使其必小于
总复杂度
::::info[AC Code]
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
struct node
{
int u,v,i;
};
node tr[maxn];
vector<node>s[maxn];
vector<int>q[maxn];
int du[maxn];
int f[maxn];
int win[maxn];
int m;
extern "C"
{
int ask(int x);
void init(int n,vector<node>e)
{
m=n;
for(int i=1;i<=n-1;i++)
{
tr[i]=e[i-1];
s[tr[i].u].push_back(node{tr[i].u,tr[i].v,i});
s[tr[i].v].push_back(node{tr[i].u,tr[i].v,i});
q[tr[i].u].push_back(tr[i].v);
q[tr[i].v].push_back(tr[i].u);
f[tr[i].u]++;f[tr[i].v]++;
}
}
string que()
{
while(1)
{
int fl=1;
for(int i=1;i<=m-1;i++)
if(du[i]==0)
fl=0;
if(fl==1)
break;
int md=0,mi=0;
for(int i=1;i<=m;i++)
if(f[i]>md)
md=f[i],mi=i;
int tmp=ask(mi);
win[mi]=tmp;
for(int i=0;i<s[mi].size();i++)
if(du[s[mi][i].i]==0)
{
du[s[mi][i].i]=((s[mi][i].u==mi)?tmp%2+1:tmp);
f[s[mi][i].u]--;
f[s[mi][i].v]--;
}
if(tmp==1)
for(int i=0;i<q[mi].size();i++)
if(win[q[mi][i]]==0)
{
win[q[mi][i]]=1;
for(int x=0;x<s[q[mi][i]].size();x++)
if(du[s[q[mi][i]][x].i]==0)
{
du[s[q[mi][i]][x].i]=((s[q[mi][i]][x].u==q[mi][i])?2:1);
f[s[q[mi][i]][x].u]--;
f[s[q[mi][i]][x].v]--;
}
}
}
string sk;
for(int i=1;i<=m-1;i++)
sk+=char(du[i]+'0');
return sk;
}
}
::::