学弟快乐营六(考前爆零赛)T1,T2及部分T3题解报告
验题报告 by idle_onlooker
T1sword
比较简单晦气的模拟。
注意点:
- 1.输出的 \(id\) 是初始编号而不是当前位置。
- 2.使用【寒川映月】时记得判断两边是否都有人。
- 3.如果受到伤害大于当前血量则输出为当前血量。
最后按照题意模拟即可。
\(code:\)
//为什么要攀登?因为山就在那里。
#include<bits/stdc++.h>
#define mrx 0x7f7f7f7f7f7f7f7f
#define int long long
using namespace std;
inline int read(){
int num=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=(num<<3)+(num<<1)+(ch^48);
ch=getchar();
}
return num*flag;
}
inline void write(int num){
if(num<0) putchar('-'),num=-num;
if(num>9) write(num/10);
putchar(num%10+'0');
}
inline void print(int num){
write(num);
putchar('\n');
}
inline void out(int num){
write(num);
putchar(' ');
}
inline int ksm(int a,int b,int mod){
int ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod,b>>=1;
}
return ans;
}
int n,x,y;
struct per{
int hea,id;
}a[110];
int now;
int flag;
void harm(int id,int x){
if(a[id].hea>=x) cout<<"T="<<flag<<" id="<<a[id].id<<" d="<<x<<'\n';
else cout<<"T="<<flag<<" id="<<a[id].id<<" d="<<a[id].hea<<'\n';
a[id].hea-=x;
}
signed main(){
now=n=read(),x=read(),y=read();
for(int i=1;i<=n;i++) a[i].hea=read(),a[i].id=i;
while(1){
flag++;
if(!now) break;
if(flag%3==0){
int k=(now+1)>>1;
if(k!=1) harm(k-1,y);
harm(k,y);
if(k!=now) harm(k+1,y);
}else harm(1,x);
n=now;now=0;
for(int i=1;i<=n;i++) if(a[i].hea>0) a[++now]=a[i];
}
return 0;
}
/*
*/
注意代码不要写的太屎山,尽量写的逻辑清楚一些。
难度:
代码难度:\(CSP-J\;T2+eps\)
阅读难度:\(CSP-J\;T2+eps\)
思维难度:\(CSP-J\;T1.5\)
有点难了,但是问题不大。
*注:\(T1\) 题目改了 \(6\) 遍,std 还错了一次,我验题的时候差点崩溃了。
T2climb
直接枚举使用第二种方式的次数即可,时间复杂度\(O(\frac{w}{k})\)。
当然,你枚举第一种方式也是可以的。
\(code:\)
//为什么要攀登?因为山就在那里。
#include<bits/stdc++.h>
#define mrx 0x7f7f7f7f7f7f7f7f
#define int long long
using namespace std;
inline int read(){
int num=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=(num<<3)+(num<<1)+(ch^48);
ch=getchar();
}
return num*flag;
}
inline void write(int num){
if(num<0) putchar('-'),num=-num;
if(num>9) write(num/10);
putchar(num%10+'0');
}
inline void print(int num){
write(num);
putchar('\n');
}
inline void out(int num){
write(num);
putchar(' ');
}
inline int ksm(int a,int b,int mod){
int ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod,b>>=1;
}
return ans;
}
int w,h,k,t;
int ans1=mrx,ans2;
signed main(){
w=read(),h=read(),k=read(),t=read();
for(int i=0;i*k<=w;i++){
int num=max(0ll,h-t*i)+i*k;
int tms=i*2+max(0ll,h-t*i);
if(num>w) continue;
if(tms<ans1){
ans1=tms;
ans2=w-num;
}
if(tms==ans1) ans2=max(ans2,w-num);
}
if(ans1==mrx) write(-1);
else out(ans1),write(ans2);
return 0;
}
/*
*/
值得一提的是,这道题搜索+卡时+大力剪枝能够获得\(98pts\)。
\(code:\)
//为什么要攀登?因为山就在那里。
#include<bits/stdc++.h>
#define mrx 0x7f7f7f7f7f7f7f7f
#define int long long
using namespace std;
inline int read(){
int num=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') flag=-1;
ch=getchar_unlocked();
}
while(ch>='0'&&ch<='9'){
num=(num<<3)+(num<<1)+(ch^48);
ch=getchar_unlocked();
}
return num*flag;
}
inline void write(int num){
if(num<0) putchar_unlocked('-'),num=-num;
if(num>9) write(num/10);
putchar_unlocked(num%10+'0');
}
inline void print(int num){
write(num);
putchar('\n');
}
inline void out(int num){
write(num);
putchar(' ');
}
inline int ksm(int a,int b,int mod){
int ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod,b>>=1;
}
return ans;
}
int w,h,k,t;
int ans1=mrx,ans2;
int solve(int x){
if(x<=0) return 0;
return min({x,x/t*2+(x-x/t*t),((x-1)/t+1)*2});
}
int use_min(int x){
if(x<=0) return 0;
return min({x,x/t*k+(x-x/t*t),((x-1)/t+1)*k});
}
void dfs(int now,int num,int tim){
if((double)clock()/CLOCKS_PER_SEC>0.08) return;//卡时,代码运行时间>0.08s直接退出搜索。
if(num<0) return ;
if(tim>ans1) return ;
if(tim==ans1&&num>=ans2) return ;
if(tim+solve(h-now)>ans1) return ;
if(use_min(h-now)>num) return ;
if(now>=h){
if(tim<ans1){
ans1=tim;
ans2=num;
}else if(tim==ans1) ans2=max(ans2,num);
return ;
}
if(k<t){
dfs(now+t,num-k,tim+2);
dfs(now+1,num-1,tim+1);
}else{
dfs(now+1,num-1,tim+1);
dfs(now+t,num-k,tim+2);
}
}
signed main(){
w=read(),h=read(),k=read(),t=read();
//w:体力h:山的高度k:消耗体力t:爬升高度
dfs(0,w,0);
if(ans1==mrx) write(-1);
else out(ans1),write(ans2);
return 0;
}
/*
*/
2025-10-26-18:03
搜索AC了!!!
//为什么要攀登?因为山就在那里。
#include<bits/stdc++.h>
#define mrx 0x7f7f7f7f7f7f7f7f
#define int long long
using namespace std;
inline int read(){
int num=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') flag=-1;
ch=getchar_unlocked();
}
while(ch>='0'&&ch<='9'){
num=(num<<3)+(num<<1)+(ch^48);
ch=getchar_unlocked();
}
return num*flag;
}
inline void write(int num){
if(num<0) putchar_unlocked('-'),num=-num;
if(num>9) write(num/10);
putchar_unlocked(num%10+'0');
}
inline void print(int num){
write(num);
putchar('\n');
}
inline void out(int num){
write(num);
putchar(' ');
}
inline int ksm(int a,int b,int mod){
int ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod,b>>=1;
}
return ans;
}
int w,h,k,t;
int ans1=mrx,ans2;
int solve(int x){
if(x<=0) return 0;
return min({x,x/t*2+(x-x/t*t),((x-1)/t+1)*2});
}
int use_min(int x){
if(x<=0) return 0;
return min({x,x/t*k+(x-x/t*t),((x-1)/t+1)*k});
}
void dfs(int now,int num,int tim){
if((double)clock()/CLOCKS_PER_SEC>0.09) return;//卡时,代码运行时间>0.09s直接退出搜索。
if(num<0) return ;
if(tim>ans1) return ;
if(tim==ans1&&num>=ans2) return ;
if(tim+solve(h-now)>ans1) return ;
if(use_min(h-now)>num) return ;
if(now>=h){
if(tim<ans1){
ans1=tim;
ans2=num;
}else if(tim==ans1) ans2=max(ans2,num);
return ;
}
dfs(now+t,num-k,tim+2);
dfs(now+1,num-1,tim+1);
}
signed main(){
w=read(),h=read(),k=read(),t=read();
//w:体力h:山的高度k:消耗体力t:爬升高度
dfs(0,w,0);
if(ans1==mrx) write(-1);
else out(ans1),write(ans2);
return 0;
}
/*
*/
原本此题的数据范围是现在的十分之一,时间也是现在的十倍,但是由于我太会剪枝,导致搜索能够直接\(AC\),出题人迫不得已做出了更改。
难度:
代码难度:\(CSP-J\;T1.5\)
阅读难度:\(CSP-J\;T1.5\)
思维难度:\(CSP-J\;T2\)
还算是比较友好的,感觉把这道题放\(T1\)会好一些。
T3decipher
考虑统计所有\(y\)对答案的贡献,对于下标为\(i\)的\(s_i=y\),他对答案的贡献为\(s_1\sim s_{i-1}\)中\(x\)的数量乘上\(s_{i+1}\sim s_{n}\)中\(z\)的数量,可以直接使用一个前缀和,一个后缀和预处理,这样就能\(O(n)\)算出一次修改的答案,此时如果代码写得好大概有\(45pts\)。

浙公网安备 33010602011771号