2024825XCPC2024模拟赛
背景
QY可爱。
榜三。
正文
记得上次打ICPC赛制还是在上一次。
而且这次是IOI赛制,所以没有罚时哈哈哈哈哈哈哈。
T1
概率期望,但是只用了定义。
\(\mathcal{O}(1)\) 小式子一推,\(6\min\) 过掉。
T2
直接上难度。
发现两个字符串按照前缀和后缀分别删除元素以后得到的两个端点之间的距离恰好就是答案,也不证明了反正没罚时,句过了。
int l=0,r=-1+t.size();
while(s[l]==t[l])l++;
while(s[r-1]==t[r])r--;
swap(l,r);
if(r-l+1<=0)return 0 * puts("0");
cout<<(r-l+1)<<endl;
T3
看了一眼是三维同余背包,因为我不会 DP 和 \(n\cdot m\cdot k \le 10^5\) 的数组开法,就先跳了。
后来可做题做完了发现全场就我一个没过T3的,然后回来补了一下,发现数组的话可以用一个巨长的 vector,如下:
vector < vector < vector < int > > > dp ( n + 10 , vector < vector < int > > ( m + 10 , vector < int > ( 19 ) ) ) ;
然后背包部分也比较好想,类似正常背包,第三位每次跟着转移就行了。
for(int i=0;i<=n+1;i++)for(int j=0;j<=m;j++)for(int k=0;k<=17;k++)dp[i][j][k]=-inf;
for(int i=0;i<=m;i++)dp[0][i][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=m;j>=0;j--)
{
for(int k=0;k<16;k++)dp[i][j][k]=dp[i-1][j][k];
for(int k=0;k<16;k++)
{
if(j>=v[i])dp[i][j][(k+w[i])%16]=max(dp[i][j][(k+w[i])%16],dp[i-1][j-v[i]][k]+1);
}
}
}
T4
说实话,我都不知道自己是怎么过的。
首先奇数个数是偶数的部分很好做。
然后其余的话胡搞一下。
发现只有 75pts,于是加了一堆特判,发现就过了……
T5
防 AK 题。
正解的话看着是 LCA+线段树+平衡树+树链剖分+…… ,但是发现直接暴力有 75pts。
T6
发现使用线段树可以秒掉,然后就秒掉了。
有 \(\mathcal{O}(n)\) 的线性做法,但是不想想了。
T7
简单二分答案,然后就简单了。
int ti=read(),x=read();
int pos=lower_bound(t+1,t+m+1,ti-a[x])-t;
if(pos==m+1)
{
cout<<"TNT"<<endl;
continue;
}
printf("%lld\n",t[pos]-(ti-a[x]));
T8
全场最大码量。
思路极其简单,代码极其恶心。
看着别人 40min 才过,我默默地先放弃了。
但是后来我发现有一个更为简单的搜索思路,可以用直接合并数字代替枚举全排列,然后就拿到了全场最简单思路。
点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
// static char buf[100000],*pa=buf,*pd=buf;
// #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
int w = 1, s = 0; char ch = getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=1e9+7;
const int maxn=5e5+10;
const int inf=1e9+7;
bool can=0;
map<string,int> mp;
double a[100];
void pre()
{
mp["A"]=1;mp["2"]=2;mp["3"]=3;
mp["4"]=4;mp["5"]=5;mp["6"]=6;
mp["7"]=7;mp["8"]=8;mp["9"]=9;
mp["10"]=10;mp["J"]=11;mp["Q"]=12;
mp["K"]=13;
}
void dfs(int n)
{
if(n==1)
{
for(int i=1;i<=4;i++)
{
if(fabs(a[i]-24)<0.01)can=1;
}
return ;
}
for(int i=1;i<=3;i++)
{
for(int j=i+1;j<=4;j++)
{
if(a[i]!=0&&a[j]!=0)
{
double x1=a[i],x2=a[j];
if(x2!=0)
{
a[i]=1.0*x1/x2;
a[j]=0;
dfs(n-1);
a[i]=x1,a[j]=x2;
}
if(x1!=0)
{
a[i]=1.0*x2/x1;
a[j]=0;
dfs(n-1);
a[i]=x1,a[j]=x2;
}
a[i]=x1+x2;
a[j]=0;
dfs(n-1);
a[i]=x1,a[j]=x2;
a[i]=x1-x2;
a[j]=0;
dfs(n-1);
a[i]=x1,a[j]=x2;
a[i]=x2-x1;
a[j]=0;
dfs(n-1);
a[i]=x1,a[j]=x2;
a[i]=x1*x2;
a[j]=0;
dfs(n-1);
a[i]=x1,a[j]=x2;
}
}
}
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
pre();
int Q=read();
while(Q--)
{
string ss;
for(int i=1;i<=4;i++)
{
cin>>ss;
a[i]=mp[ss]*1.0;
}
dfs(4);
puts(can?"YES":"NO");
can=0;
}
return 0;
}
T9
lg 公开赛原题。
把每个数字翻转的次数和最后的位置找到,然后就没了。
for(int i=1;i<=m;i++)
{
int t=m-i+1;
if(t&1) f[i]=!f[i];
}
for(int i=1;i<=m;i++)
{
int t=m-i+1;
if(t&1)
{
t=(t+1)/2;
ans[t]=f[i];
}
else
{
t/=2;
int st=1+i;
ans[t+st-1]=f[i];
}
}
T10
赛时一直没过,赛后发现是一个排序后的 DP。
全场只有 WLX 大佬过了。
T11
很缝合的一个题。
根据提示把要找的东西分成三类。
三度点比较好找,把每个点的度数处理出来,然后加加减减就行了。
链的话可以预处理一元度数和二元度数,但是这样会和三角形冲突,所以需要再找到冲突数量减一下。
对于三角形,其实就是三元环计数。由度数大的点连向度数小的点建立新图,发现可以过。
然后就可以了。
T12
要求优化题目程序。
看出来了约瑟夫环,但是因为不会线段树二分导致……。
好尴尬啊(
总结
出的挺好,饭都没得吃了,下次别出了。