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

浙公网安备 33010602011771号