20260418 模拟赛 总结

C 题挂分了 /ll 不然我会有 \(584\) 的啊!!!111(绝望


A - 修改密码

简单题,随便统计、模拟几下就好了,细节就不多不说了。

戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define Uint unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
#define umap unordered_map
using namespace std;
int T,n;
int a,b,c,A,B,C;
string s;
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
int main(){
    T=read();
    while(T--){
        cin>>s;
        n=s.size(),s=" "+s;
        a=0,b=0,c=0,A=0,B=0,C=0;
        for(int i=1;i<=n;i++){
            char h=s[i];
            if(h>='A'&&h<='Z'){//大写字母
                if(h=='O')a++;
                else A++;
            }
            else if(h>='a'&&h<='z'){//小写字母
                if(h=='o')b++;
                else B++;
            }
            else{//数字
                if(h=='0')c++;
                else C++;
            }
        }
        int cnt=0;
        if(a+A==0)cnt++;
        if(b+B==0)cnt++;
        if(c+C==0)cnt++;
        if(cnt==0)cout<<"0\n";
        else if(cnt==1){
            int ans=-1;
            if(a>0&&a-1+A>0)ans=1;
            if(b>0&&b-1+B>0)ans=1;
            if(c>0&&c-1+C>0)ans=1;
            cout<<ans<<"\n";
        }else if(cnt==2){
            int ans=-1;
            if(a>1&&a-2+A>0)ans=2;
            if(b>1&&b-2+B>0)ans=2;
            if(c>1&&c-2+C>0)ans=2;
            cout<<ans<<"\n";
        }else{
            cout<<"-1\n";
        }
    }
    return 0;
}

B - 灯塔

依旧简单题,对电量序列排序并去重后,依次枚举,贪心来做,能点亮就点亮,同步统计点亮灯塔的数量。不难证明这个贪心是对的。

戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define Uint unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
#define umap unordered_map
using namespace std;
const int N = 1e6+5;
int m,n,a[N],lst,cnt;
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}

int main(){
    m=read(),n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    sort(a+1,a+n+1);
    n=unique(a+1,a+n+1)-a-1;
    lst=-1,cnt=0;
    for(int i=1;i<=n;i++)
        if(a[i]-lst>1)cnt++,lst=a[i];
    cout<<cnt<<"\n";
    return 0;
}

C - 三角形构造

\(x \space \text{or} \space y \ge x,y\),但 \(x \space \text{or} \space y \le x+y\),显然当且仅当 \(x \space \text{or} \space y = x+y\) 时才是不可能围成合法三角形的,等价于 \(x\) 二进制下为 \(1\) 的位置 \(y\) 都不能为 \(1\)。统计 \(x\) 有多少个二进制下的 \(0\)(前导零不算),假设为 \(cnt\) 个,那么答案就是 \(2^{cnt}-1\),之所以要 \(-1\) 是因为 \(y\) 不能为 \(0\)。

我是扇贝吧我赛时写了个数位 DP 结果还写错了,痛失 \(70\) 分也是没谁了嗯对。

戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define Uint unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
#define umap unordered_map
using namespace std;
LL num,kk,a[25],dp[25][2],Ans;
stack<int> st;
LL read(){
    LL su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}

int main(){
    num=read(),kk=num,Ans=1;
    while(num){
        if(num%2==0)Ans*=2ll;
        num/=2;
    }cout<<kk-Ans+1<<"\n";
    return 0;
}

D - 免费披萨

位数太小了,直接暴力搜索就结束了,比 C 简单。C 好歹要一点点思维。

戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define Uint unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
#define umap unordered_map
using namespace std;
LL n,a[20],Ans,maxg;
LL read(){
    LL su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
LL GCD(LL x,LL y){
    if(x<y)swap(x,y);
    return (y?GCD(y,x%y):x);
}
LL calc(LL x,LL ad){
    LL numb=0;
    if(ad==0)numb=x;
    for(int i=1;i<=8;i++){
        numb=numb*10+a[i];
        if(i==ad)numb=numb*10+x;
    }return numb;
}
void sol(){
    for(int x=1;x<=8;x++)
        for(int ad=0;ad<=8;ad++){
            LL numb=calc(x,ad);
            LL g=GCD(numb,n);
            if(g>maxg)Ans=numb,maxg=g;
            else if(g==maxg&&numb<Ans)Ans=numb;
        }
}
void DFS(int u){
    if(u>8){sol();return;}
    for(int i=1;i<=8;i++){
        if(a[i])continue;
        a[i]=u;DFS(u+1);a[i]=0;
    }return;
}
int main(){
    n=read();
    Ans=0,maxg=0;
    DFS(1);
    cout<<Ans<<"\n";
    return 0;
}

E - 魔法护盾

终于来了个难点的题了(难吗?这明明很无脑啊?

全场唯一正常题,前面的题太水了,最后一题太那啥了。

我们想到令 \(dp_{i,j}\) 表示进行到第 \(i\) 回合且当前的魔法护盾数量为 \(j\) 的情况下使用的最少“护盾增幅”次数。感觉有点爆炸,老师说可以把“护盾增幅”次数设计进状态,但是不就是个 \(5\) 的常数吗,怕啥。没必要。

然后就是开心转移啦!肯定是扩散型对吧,从 \(dp_{i,j}\) 可以转移到 \(dp_{i+1,\min(c,j+s_{i+1})}\) 或 \(dp_{i+1,\min(c,j+2s_{i+1})}\),后者使用了“护盾增幅”而前者没有使用。

空间是会爆炸的(吧,所以滚动数组一下就结束了。

戳这里看代码
#include<bits/stdc++.h>
#define LL long long
#define Uint unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
#define umap unordered_map
using namespace std;
const int N = 50005;
const int INF = 0x3f3f3f3f;
int n,c,b,s[N],a[N];
int dp[N],f[N],Ans;
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
void swap_dpf(){
    for(int i=0;i<=c;i++)
        f[i]=dp[i],dp[i]=INF;return;
}
int main(){
    n=read(),c=read(),b=read();
    b=min(b,c);
    for(int i=1;i<=n;i++)s[i]=read();
    for(int i=1;i<=n;i++)a[i]=read();
    memset(dp,0x3f,sizeof(dp));
    dp[b]=0,Ans=INF;
    for(int i=1;i<=n;i++){
        swap_dpf();
        for(int w=0;w<=c;w++){
            int w1=min(c,w+s[i]);
            int w2=min(c,w+2*s[i]);
            if(w1>=a[i])dp[w1]=min(dp[w1],f[w]);
            if(w2>=a[i])dp[w2]=min(dp[w2],f[w]+1);
        }
    }for(int i=0;i<=c;i++)Ans=min(Ans,dp[i]);
    cout<<(Ans==INF?-1:Ans)<<"\n";
    return 0;
}

F - 机器人充电站规划

一个非常 shit 的题。

二分,二分这个什么最大负载率的最小可能值,check 主要就是判断能不能把所有机器人都塞进去。

我最开始写了一个贪心,但是是假的,虽然我并不知道怎么 hack,不过也是非常侥幸拿到了 \(84\) 分,耶!

正解是滚木。/咦

呸呸呸,正解是那什么爆搜剪枝优化,喵了的个咪的,这么难剪枝,我什么记忆化哈希啊全局最优性啊排序优化啊都加遍了,甚至还用假贪心先预判了一波,但还是死活过不去啊!!!\(98\) 分,\(98\) 分,\(98\) 分,谁懂我有多绝望?

放弃了,卡常不好玩,那 \(2\) 分不要也罢。

戳这里看赛时代码(84 分)
#include<bits/stdc++.h>
#define LL long long
#define Uint unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
#define umap unordered_map
using namespace std;
const int N = 1005;
int n,k,t[N],c[N],cnt,l,r,Ans;
double p[N],sum[N];
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
bool check(double up){
    up+=0.5;
    for(int i=1;i<=k;i++)sum[i]=up;
    sum[0]=10000000.0;
    for(int i=cnt;i>=1;i--){
        int id=0;
        for(int j=1;j<=k;j++)
            if(sum[j]>p[i]&&sum[j]<sum[id])id=j;
        if(!id)return 0;
        sum[id]-=p[i];
    }return 1;
}
int main(){
    n=read(),k=read();
    for(int i=1;i<=n;i++)t[i]=read(),c[i]=read();
    for(int i=1;i<=n;i++){
        int r=read();
        double P=(double)(c[i])/t[i]*100.0;
        while(r--)p[++cnt]=P;
    }sort(p+1,p+cnt+1);
    l=0,r=100,Ans=100;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid+0.0))Ans=mid,r=mid-1;
        else l=mid+1;
    }cout<<Ans<<"\n";
    return 0;
}
戳这里看赛后代码(98 分)
#include<bits/stdc++.h>
#define LL long long
#define Uint unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
#define umap unordered_map
using namespace std;
const int N = 1005;
const double eps = 1e-3;
const LL Bas = 2333;
const LL MOD = 1000000000000031;
int n,k,t[N],c[N],cnt,Ans;
LL mul[N]={47,3,17,97,23,29,53,13,7,83,37};
double p[N],sum[N],lst[N],l,r,ans;
umap<LL,bool> mp;
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
bool cmp(double x,double y){return x>y;}
bool easy_tan(double up){
    for(int i=1;i<=k;i++)sum[i]=up;
    sum[0]=10000000.0;
    for(int i=1;i<=cnt;i++){
        int id=0;
        for(int j=1;j<=k;j++)
            if(sum[j]>p[i]&&sum[j]<sum[id])id=j;
        if(!id)return 0;
        sum[id]-=p[i];
    }return 1;
}
LL Hash(int u,vector<double> now){
    LL hsh=u*mul[0]%MOD;
    for(int i=0;i<now.size();i++){
        LL x=(int)(now[i]*100);
        hsh=(hsh*Bas+x*mul[i+1])%MOD;
    }return hsh;
}
bool DFS(double up,int u,vector<double> now,double sum){
    if(u>cnt)return 1;
    if(lst[u]>sum)return 0;
    sort(now.begin(),now.end());
    LL sta=Hash(u,now);
    if(mp.count(sta))return 0;
    for(int i=0;i<now.size();i++){
        if(i&&now[i]==now[i-1])continue;
        if(now[i]<p[u])continue;
        now[i]-=p[u];
        if(DFS(up,u+1,now,sum-p[u]))return 1;
        now[i]+=p[u];
        if(abs(now[i]-p[u])<eps)break;
        if(abs(now[i]-up)<eps)break;
    }mp[sta]=1;return 0;
}
bool check(double up){
    if(easy_tan(up))return 1;
    vector<double> now;now.clear();
    for(int i=1;i<=k;i++)now.pb(up);
    return DFS(up,1,now,up*k);
}
int main(){
    n=read(),k=read();
    for(int i=1;i<=n;i++)
        t[i]=read(),c[i]=read();
    for(int i=1;i<=n;i++){
        int r=read();
        double P=(double)(c[i])/t[i]*100.0;
        while(r--)p[++cnt]=P;
    }sort(p+1,p+cnt+1,cmp);
    for(int i=cnt;i>=1;i--)lst[i]=lst[i+1]+p[i];
    l=0.0,r=100.0,ans=100.0;
    while(r-l>eps){
        double mid=(l+r)/2;
        if(check(mid))ans=mid,r=mid;
        else l=mid;
    }Ans=round(ans);
    cout<<Ans<<"\n";
    return 0;
}

Summary

我错了我错了我学数位 DP 学傻了我再也不大炮打蚊子了 /ll

F 题是神秘题,这个吧,一般赛时没人会去想到正解是爆搜加剪枝吧?一般很难有这种题啊?而且这个题也不要太卡人啊?算了,这种题正赛上还是不太会出现的(确信

/fendou

posted @ 2026-04-21 20:59  嘎嘎喵  阅读(53)  评论(0)    收藏  举报