『模拟赛』暑假集训CSP提高模拟24
Rank
G
A. 与和
签。不过因为忘了 and 是啥被控 40min 还是太蒻了
对 \(a\) 进行二进制拆分,1 是 \(x\) 和 \(y\) 共有的,直接乘 2 计入和内,0 说明二者中最多出现一个 1,倍增思想,倒序枚举,若计入和后不超过 \(s\) 则计入,否则跳过,最终比较和与 \(s\) 的大小关系即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Ratio=0;
ll a,b,x,y,sum;
int num[105],nm;
namespace Wisadel
{
ll Wqp(ll x,int y)
{
ll res=1;
while(y){if(y&1) res=res*x;x=x*x;y>>=1;}
return res;
}
short main()
{
freopen("and.in","r",stdin),freopen("and.out","w",stdout);
int T;scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&a,&b);memset(num,0,sizeof num);sum=0,nm=0;
while(a) num[nm++]=a&1,a>>=1;
for(int i=0;i<nm;i++)
if(num[i]) sum+=2*Wqp(2,i);
for(int i=60;i>=0;i--)
{
if(num[i]) continue;
if(Wqp(2,i)+sum<=b) sum+=Wqp(2,i);
}
if(sum==b) printf("Yes\n");
else printf("No\n");
}
return Ratio;
}
}
int main(){return Wisadel::main();}
B. 函数
原[ABC366F] Maximum Composition
签\(\times 2\,\)。不过没签上
一个显然的选择策略,设 \(f_1\left(x\right)=A_1x+B_1\),\(f_2\left(x\right)=A_2x+B_2\),那么若 \(f_1\left(f_2\left(x\right)\right)\lt f_2\left(f_1\left(x\right)\right)\),则化简后可得:
以此类推,可以得到一个结论:越大的 \(B\) 越靠前值越大;越大的 \(A\) 越靠后值越大。但二者是并列关系,于是就蒙了,所以就胡乱打了个两种情况各取最优的 \(k\) 个然后枚举一遍,结果小点全挂喜提 69pts。
正解是 dp,我们按照上面的原则排序,定义 \(f_{i,j}\) 为到第 \(i\) 位选了 \(j\) 个的最大值,那么状态转移方程显然为:
同时,记得赋初始值 \(f_{i,j}=f_{i-1,j}\) 以及边界 \(f_{0,0}=1\)。
时间复杂度 \(\mathcal{O(n^2)}\)。
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
using namespace std;
typedef long long ll;
inline int qr()
{
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#define qr qr()
const int Ratio=0;
const int N=2e5+5;
int n,k;
struct rmm
{
int a,b;
bool operator<(const rmm &A)const{return a*A.b+b<A.a*b+A.b;}
}a[N];
ll f[N][15];
namespace Wisadel
{
short main()
{
freopen("func.in","r",stdin),freopen("func.out","w",stdout);
n=qr,k=qr;f[0][0]=1;
fo(i,1,n) a[i].a=qr,a[i].b=qr;
sort(a+1,a+1+n);
fo(i,1,n) fo(j,0,k)
{
f[i][j]=f[i-1][j];
if(j) f[i][j]=max(f[i][j],f[i-1][j-1]*a[i].a+a[i].b);
}
printf("%lld\n",f[n][k]);
return Ratio;
}
}
int main(){return Wisadel::main();}
C. 袋鼠
一眼简单,再一眼没思路。
赛时打了暴搜,\(n\ge 15\) 就寄了,然后打表一共 12pts。
正解是很神的插入法 dp,首先将我们跳转的顺序转化成序列,那么就成为了求序列以 \(s\) 开头以 \(t\) 结尾的序列合法的个数。状态定义为 \(f_{i,j}\) 表示已经插入了前 \(i\) 个数并且当前序列被分成 \(j\) 段的个数,那么转移时只有三种情况:
- 新开一个连续段,此时 \(i\) 大于前面任何数,所以可以随便插,方案数为 \(j\);但开头结尾已经确定,所以 \(i\gt s\) 或 \(i\gt t\) 时 \(j\) 分别要减一;状态转移方程为:
- 新加入的 \(i\) 将两个连续段连接起来,同理可以随便插,方案数为 \(j\),状态转移方程为:
- 新加入的 \(i\) 为 \(s\) 或 \(t\),此时只有一种情况即将其置于头或尾,可以单独成段或连上相邻的一段,转移方程为:
时间复杂度 \(\mathcal{O(n^2)}\)。
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
typedef long long ll;
const int Ratio=0;
const int N=2e3+5;
const int mod=1e9+7;
int n,st,ed,ans;
ll f[N][N];
namespace Wisadel
{
short main()
{
freopen("kang.in","r",stdin),freopen("kang.out","w",stdout);
scanf("%d%d%d",&n,&st,&ed);f[1][1]=1;
fo(i,2,n) fo(j,1,i)
{
if(i!=st&&i!=ed) f[i][j]=(j*f[i-1][j+1]%mod+(j-(i>st)-(i>ed))*f[i-1][j-1]%mod)%mod;
else f[i][j]=f[i-1][j-1]+f[i-1][j];
}
printf("%lld\n",f[n][1]);
return Ratio;
}
}
int main(){return Wisadel::main();}
D. 最短路
赫拉格老爷子你说你游戏里公招控我就算了到题面上还这么难
还有,
为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?为什么没有棘刺的题?
快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!快出道棘刺的题啊啊!
咳
赛时想了有正确性的错解,由于边权都是 \(2\) 的幂,因此我们只要记下最短路边权的所有指数就可以正常地操作更新了,不过实现要依靠优先队列所以时间上直接 T 飞了啊,还没有图小一点的测试点所以直接保龄,还不如暴力硬上 Dijkstra 能拿 8pts。
正解需要高精度,哈希,主席树,感觉这实现起来比黑题还黑题。
末
也许锣鼓的运势影响心情?今天大凶,前几天都大吉。
前三道都不难,感觉如果出到三场模拟赛的 T1 就都能切吧?
还有就是没思路了就考虑 dp,大概率是这样的,如果状态设计差不多就能拿不少分。