【比賽記錄】2025CSP-S模擬賽13
| A | B | C | D | Sum | Rank |
|---|---|---|---|---|---|
| 100 | - | 30 | 10 | 140 | 6/20 |
今天使用了表格??
A. 馬
新題的數據很水,可能有許多正確率較高的貪心能夠通過。
正解是 \(O(m^3)\) 的 DP,然而我寫的是 \(O(nm^3)\) 的(
設 \(f_{i,x,y,z}\) 表示前 \(i\) 匹馬總共 \(x\) 次大圈,\(y\) 次小圈,\(z\) 次過河,前 \(i-1\) 匹馬的疲勞值都 \(\le 100\),第 \(i\) 匹馬的最小疲憊值。轉移時可以從上一匹馬轉,也可以當前這匹馬轉。需要滾動數組。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int inf=1e9;
int n,m,a,b,c,f[2][305][305][305],ans;
il void dfs(int x,int ra,int rb,int rc){
if(x>n){
// if(m-ra-rb-rc==9){
// cout<<"---------------------------------------------\n";
// cout<<hp[1][1]<<" "<<hp[1][2]<<" "<<hp[1][3]<<"\n";
// cout<<hp[2][1]<<" "<<hp[2][2]<<" "<<hp[2][3]<<"\n";
// cout<<hp[3][1]<<" "<<hp[3][2]<<" "<<hp[3][3]<<"\n";
// cout<<"---------------------------------------------\n";
// }
ans=max(ans,m-ra-rb-rc);
return ;
}
for(int i=0;i<=ra;i++){
for(int j=0;j<=rb;j++){
for(int k=0;k<=rc;k++){
if(i*50+j*20+(1<<k)<=100){
// hp[x][1]=i,hp[x][2]=j,hp[x][3]=k;
dfs(x+1,ra-i,rb-j,rc-k);
}
}
}
}
}
il void upd(int &x,int y){
x=x<y?x:y;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>a>>b>>c;
if(n<=10&&m<=10){
dfs(1,a,b,c);
cout<<ans;
return 0;
}
for(int x=0;x<=a;x++){
for(int y=0;y<=b;y++){
for(int z=0;z<=c;z++){
f[0][x][y][z]=inf;
}
}
}
f[0][0][0][0]=1;
for(int i=1,j=1;i<=n;i++,j^=1){
for(int x=0;x<=a;x++){
for(int y=0;y<=b;y++){
for(int z=0;z<=c;z++){
f[j][x][y][z]=inf;
}
}
}
f[j][0][0][0]=1;
for(int x=0;x<=a;x++){
for(int y=0;y<=b;y++){
for(int z=0;z<=c;z++){
int &res=f[j][x][y][z];
if(f[j^1][x][y][z]<=100){
res=1;
continue;
}
if(x){
if(f[j^1][x-1][y][z]<=100){
upd(res,51);
}
else{
upd(res,min(f[j][x-1][y][z]+50,inf));
}
}
if(y){
if(f[j^1][x][y-1][z]<=100){
upd(res,21);
}
else{
upd(res,min(f[j][x][y-1][z]+20,inf));
}
}
if(z){
if(f[j^1][x][y][z-1]<=100){
upd(res,2);
}
else{
upd(res,min(f[j][x][y][z-1]<<1,inf));
}
}
}
}
}
}
for(int x=0;x<=a;x++){
for(int y=0;y<=b;y++){
for(int z=0;z<=c;z++){
if(f[n&1][x][y][z]<=100){
ans=max(ans,x+y+z);
}
}
}
}
cout<<ans;
return 0;
}
}
int main(){return asbt::main();}
B. 可愛捏
大體思路是,將每個數分解質因數,去掉所有立方因子后能組成完全立方數的數是一一對應的,在兩坨中去更大的一坨就好了。瓶頸在于分解質因數。
考慮根號分治。首先分出所有 \(\le\sqrt[3]{a_i}\) 的質因數,剩下的就是兩個質數相乘了。使用歐拉篩,每次分解質因數的時間復雜度都是 \(O(\sqrt[3]{a_i})\) 的。
Code
#include<bits/stdc++.h>
#define int long long
#define il inline
#define fir first
#define sec second
using namespace std;
namespace asbt{
const int maxn=3e3+5;
int n,ans,prn,prm[maxn],hp1[15],hp2[15];
bool npr[maxn];
map<__int128,int> cnt;
map<__int128,__int128> ying;
il void euler(int x=3e3){
for(int i=2;i<=x;i++){
if(!npr[i]){
prm[++prn]=i;
}
for(int j=1;j<=prn&&i*prm[j]<=x;j++){
npr[i*prm[j]]=1;
if(i%prm[j]==0){
break;
}
}
}
}
il int qpow(int x,int y){
return y==0?1:y==1?x:x*x;
}
int main(){
// freopen("lovely07.in","r",stdin);
ios::sync_with_stdio(0),cin.tie(0);
euler();
cin>>n;
int ans=0;
while(n--){
int x,tot=0;
cin>>x;
// cout<<x<<"\n";
for(int i=1;i<=prn;i++){
if(x%prm[i]==0){
hp1[++tot]=prm[i];
while(x%prm[i]==0){
x/=prm[i];
hp2[tot]++;
}
}
}
for(int i=1;i<=prn;i++){
if(x%prm[i]==0){
x/=i;
if(x==i){
hp1[++tot]=i;
hp2[tot]=2;
}
else{
hp1[++tot]=i;
hp2[tot]=1;
hp1[++tot]=x;
hp2[tot]=1;
}
goto togo;
}
}
if(x!=1){
hp1[++tot]=x;
hp2[tot]=1;
}
togo:;
// cout<<tot<<"\n";
// for(int i=1;i<=tot;i++){
// cout<<hp1[i]<<" "<<hp2[i]<<"\n";
// }
__int128 a=1,b=1;
for(int i=1;i<=tot;i++){
hp2[i]%=3;
a*=qpow(hp1[i],hp2[i]);
b*=qpow(hp1[i],(3-hp2[i])%3);
}
if(a==1){
if(!ans){
ans++;
}
}
else{
cnt[a]++;
ying[a]=b,ying[b]=a;
}
for(int i=1;i<=tot;i++){
hp1[i]=hp2[i]=0;
}
}
// cerr<<clock()<<"\n";
for(auto i:ying){
__int128 x=i.fir,y=i.sec;
ans+=max(cnt[x],cnt[y]);
}
cout<<(ans+1)/2;
return 0;
}
}
signed main(){return asbt::main();}
C. 詩
根號分治*2。
考慮對于所有長度 \(\le B\) 的字符串,暴力預處理出文本串中的所有可能的子串,二分查找;長度 \(>B\) 的字符串,直接在文本串中暴力查找。據傳 \(B=100\) 時最優。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define ull unsigned ll
#define lwrb lower_bound
#define uprb upper_bound
using namespace std;
namespace asbt{
const int maxn=1e5+5,B=100;
const ull bas1=1e6+151;
int opt,n,m,a[maxn],b[maxn],cnt[105];
ull pw1[maxn],ha1[maxn],hp[105][maxn];
il ull gha1(int l,int r){
return ha1[r]-ha1[l-1]*pw1[r-l+1];
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>opt>>n>>m;
pw1[0]=1;
for(int i=1;i<=n;i++){
cin>>a[i];
pw1[i]=pw1[i-1]*bas1;
ha1[i]=ha1[i-1]*bas1+a[i];
}
for(int i=1;i<=B;i++){
for(int l=1,r=i;r<=n;l++,r++){
hp[i][++cnt[i]]=gha1(l,r);
}
sort(hp[i]+1,hp[i]+cnt[i]+1);
}
int ans=0;
while(m--){
int k;
ull hb1=0;
cin>>k;
for(int i=1;i<=k;i++){
cin>>b[i];
if(opt){
b[i]^=ans;
}
hb1=hb1*bas1+b[i];
}
ans=0;
if(k<=B){
ans=uprb(hp[k]+1,hp[k]+cnt[k]+1,hb1)-lwrb(hp[k]+1,hp[k]+cnt[k]+1,hb1);
}
else{
for(int l=1,r=k;r<=n;l++,r++){
if(hb1==gha1(l,r)){
ans++;
}
}
}
cout<<ans<<"\n";
}
return 0;
}
}
int main(){return asbt::main();}
D. 相似
首先有一個轉化:將 \(G_i\) 改為 \(G_i\) 在 \(S_i\) 中的位置,于是要求變為一段區間值連續,即 \(max-min+1=len\)。
對于 \(k=1\) 的部分分(30pts),考慮移動右端點,用線段樹維護 \([i,r]\) 的 \(max-min-len\)。其中 \(len\) 是好維護的,\(max\) 和 \(min\) 可以用單調棧維護。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define lid id<<1
#define rid id<<1|1
using namespace std;
namespace asbt{
const int maxn=2e5+5;
int n,m,a[maxn],b[maxn],pos[maxn];
int st1[maxn],tp1,st2[maxn],tp2,tag[maxn<<2];
struct node{
int val,num;
node(int val=0,int num=1):val(val),num(num){}
il node operator+(const node &x)const{
if(val<x.val){
return *this;
}
if(val>x.val){
return x;
}
return node(val,num+x.num);
}
}tr[maxn<<2];
il void pushup(int id){
tr[id]=tr[lid]+tr[rid];
}
il void pushtag(int id,int v){
tag[id]+=v,tr[id].val+=v;
}
il void pushdown(int id){
if(tag[id]){
pushtag(lid,tag[id]);
pushtag(rid,tag[id]);
tag[id]=0;
}
}
il void add(int id,int L,int R,int l,int r,int v){
if(L>=l&&R<=r){
pushtag(id,v);
return ;
}
pushdown(id);
int mid=(L+R)>>1;
if(l<=mid){
add(lid,L,mid,l,r,v);
}
if(r>mid){
add(rid,mid+1,R,l,r,v);
}
pushup(id);
}
il node query(int id,int L,int R,int l,int r){
if(L>=l&&R<=r){
return tr[id];
}
pushdown(id);
int mid=(L+R)>>1;
if(r<=mid){
return query(lid,L,mid,l,r);
}
if(l>mid){
return query(rid,mid+1,R,l,r);
}
return query(lid,L,mid,l,r)+query(rid,mid+1,R,l,r);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
pos[a[i]]=i;
}
for(int i=1;i<=n;i++){
cin>>b[i];
b[i]=pos[b[i]];
}
ll ans=0;
for(int i=1;i<=n;i++){
add(1,1,n,1,i,-1);
while(tp1&&b[st1[tp1]]<=b[i]){
add(1,1,n,st1[tp1-1]+1,st1[tp1],b[i]-b[st1[tp1]]);
tp1--;
}
while(tp2&&b[st2[tp2]]>=b[i]){
add(1,1,n,st2[tp2-1]+1,st2[tp2],b[st2[tp2]]-b[i]);
tp2--;
}
st1[++tp1]=st2[++tp2]=i;
ans+=query(1,1,n,1,i).num;
}
cout<<ans;
return 0;
}
}
int main(){return asbt::main();}

浙公網安備 33010602011771號