csp 赛前练习
其实是复健。上一次碰电脑是期末考试完(7月),上上次是 noip(2023 年 11 月)。
1.P9752 [CSP-S 2023] 密码锁__record
要求:语文没问题,会基础语法,有生活常识。枚状态,判断。几乎没有复杂度要求。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,ans;
int a[8];
int q[N][8];
void dfs(int t){
if(t==5){
for(int i=1;i<=n;i++){
int f=0;
for(int j=1;j<=5;j++){
if(a[j]!=q[i][j]){
f=1;break;
}
}
if(!f) return;
int pre=-1,num=0;
for(int j=1;j<=5;j++){
if(a[j]!=q[i][j]){
if(num&&(num!=j-1||num==6)) return;
if(pre!=-1&&pre!=(a[j]-q[i][j]+10)%10) return;
pre=(10+a[j]-q[i][j])%10;
if(num) num=6;
else num=j;
}
}
}
ans++;
return;
}
for(int i=0;i<=9;i++){
a[t+1]=i;
dfs(t+1);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=5;j++) scanf("%d",&q[i][j]);
dfs(0);
printf("%d",ans);
return 0;
}
2.P9753 [CSP-S 2023] 消消乐__record
去年糊了一个 35 的暴力,现在也没看懂当时咋写的,有点复杂。
50pts 的 n^2 暴力还是可想的。发现这个消消乐能用栈维护,于是枚举左右段点也就是枚所有子串,用栈处理。栈消空了即说明可以统计答案。
接下来考虑一个性质:如果 s[1,l],s[l+1,r] 都可消,则 s[l,r] 可消;另一个性质:如果用栈维护的序列,在进、出元素后又回到了之前的状态,则说明中间的这段消掉了。
于是把每次操作完的状态哈希后用 map 维护,统计出现的各种状态。这样就把能消的子串都整合起来了。
Code
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
using namespace std;
const int N=2e6+10;
const ull P=1331;
int n,t;
char a[N],s[N];
ll ans;
ull k,p[N];
map<ull,ll> cnt;
void init(){
p[1]=1;
for(int i=2;i<=N;i++) p[i]=p[i-1]*P;
}
int main(){
scanf("%d",&n);
cin>>a+1;
init();
cnt[k]=1;
for(int i=1;i<=n;i++){
if(t&&s[t]==a[i]) k-=(s[t]-'a'+1)*p[t],t--;
else s[++t]=a[i],k+=(s[t]-'a'+1)*p[t];
ans+=cnt[k];
cnt[k]++;
}
printf("%lld",ans);
return 0;
}
(这个人很愚蠢,看 luogu 第一篇题解没有看懂,只是大受震撼)
3.P3131 [USACO16JAN] Subsequences Summing to Sevens S
随机做了道橙题然后发现不会,,完了这个人啥也不会了只会写暴力了而且赛事暴力还写不对,,,,,有点破防了呀兄弟,,,
暴力莽了 96 然后就水灵灵的滚去看题解了。
前缀和不用说。考虑一个区间能整除 7,则区间左右端点前缀和值 mod 7 一定相等。这个意义上和消消乐有点像了,就是如果你中间这段满足条件那就能消掉,消掉则对区间左右端点不会产生任何影响。别忘了第一个出现模数为 0 的地方是序列最开头。
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4+10;
int n,ans;
int a[N],mn[10],mx[10];
int s[N];
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;i++){
a[i]=s[i]%7;
if(!mn[a[i]]) mn[a[i]]=i;
mx[a[i]]=i;
}
for(int i=0;i<7;i++) if(mx[i]) ans=max(ans,mx[i]-mn[i]);
printf("%lld",max(ans,mx[0]));
return 0;
}
4.P3612 [USACO17JAN] Secret Cow Code S
学 oi 4 年,独立完成一道小小橙题,实力捏!
()
分治,模拟。多练这类小题或许有利于我身心的健康,记忆的恢复。
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=32;
char s[N];
int l,cnt=1;
ll n,res=1;
ll t[1145];
int main(){
cin>>s+1;
int l=strlen(s+1);
scanf("%lld",&n);
res=res*l;
t[1]=l;
while(res<n){
res<<=1;
t[++cnt]=res;
}
for(int i=cnt;i>1;i--){
if(n<=t[i-1]) continue;
if(n==t[i-1]+1) n--;
else n-=t[i-1]+1;
}
cout<<s[n];
return 0;
}
赤裸裸的二维前缀和板子,呃呃之前怎么没有提交过。/jy
Code
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+4;
int n,m;
int a,b,ans;
int s[N][N],q[N][N];
int main(){
//本题所有坐标加一防止越界
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
q[x+1][y+1]+=z;
a=max(a,x+1),b=max(b,y+1);
}
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+q[i][j];
for(int i=1;i+m-1<N;i++){
for(int j=1;j+m-1<N;j++){
int t=s[i+m-1][j+m-1]-s[i-1][j+m-1]-s[i+m-1][j-1]+s[i-1][j-1];
ans=max(ans,t);
}
}
printf("%d",ans);
return 0;
}
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+10;
int n;
ll ans;
int a[N],b[N];
void msort(int l,int r){
if(l>=r) return;
int mid=(l+r)>>1;
msort(l,mid),msort(mid+1,r);
int i=l,j=mid+1,k=0;
while(i<=mid&&j<=r){
if(a[i]<=a[j]) b[++k]=a[i++];
else{
b[++k]=a[j++];
ans+=mid-i+1;
}
}
while(i<=mid) b[++k]=a[i++];
while(j<=r) b[++k]=a[j++];
for(int i=l;i<=r;i++) a[i]=b[i-l+1];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
msort(1,n);
printf("%lld",ans);
return 0;
}
有个小朋友一开始忘了二分答案的板子应该怎么写,于是很错误的二分并陷入了死循环((
这么水的二分答案也能绿。是为了照顾像我这样不会写板子的人吗?感觉思维量还不如前面两个小橙题。
Code
#include<bits/stdc++.h>
#define ll long long
const int N=1e5+10;
using namespace std;
int n,k;
ll as1=-1,as2=-1;
int a[N];
ll check(ll x){
ll cnt=0,tot=0;
for(int i=1;i<=n;i++){
tot+=a[i];
tot=max(tot,0ll);
if(tot>=x) cnt++,tot=0;
}
return cnt;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ll l=1,r=1e18,mid=0;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)<=k){
r=mid-1;
if(check(mid)==k) as1=mid;
}
else l=mid+1;
}
l=1,r=1e18,mid=0;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)>=k){
l=mid+1;
if(check(mid)==k) as2=mid;
}
else r=mid-1;
}
if(as1==-1) puts("-1");
else printf("%lld %lld",as1,as2);
return 0;
}
奖励自己一道猪国杀。不过已经提交了 20 多发了,极其难评,刚刚 45pts。先咕一下。
又一道意难平。至今找不到去年源文件,突然无法确定我 t1 到底是不是因为没有判 n = 1 挂掉的。大概吧。也不重要了。
原来就简单的小模拟啊,统计一下序列的升序降序。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=3e3+5;
int n,m;
string s;
int mx[N],mn[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
cin>>s;
mx[i]=0,mn[i]=33;
for(int j=0;j<m;j++){
mx[i]=max(mx[i],s[j]-'a'+1);
mn[i]=min(mn[i],s[j]-'a'+1);
}
}
for(int i=1;i<=n;i++){
int ans=1;
for(int j=1;j<=n;j++){
if(i==j) continue;
if(mx[j]<=mn[i]){
ans=0;
break;
}
}
cout<<ans;
}
}
继续继续,又是意难平。赛时只会模拟,大概算法没学透彻,思考也不到位吧。好像是爆零了。看着讨论区里“这题送分有啥意义吗”,陷入了思考。有意义啊,我不在这吗。
然后想了十分钟顺利的写完了。没有刷新就跳出来的 accept 让我多少有点,破防啊。
火车头往两边走,最重要的是如何让这些重合的区间连起来。如果把 m 个区间的 l~r 都枚举出来,那么时间就爆掉了。所以想一下啥玩意能 O(n) 的传递这种信息。
然后想到了差分。维护每个位置有几个行程会经过。维护一下每次行程的起始点区分方向即可。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,x;
int s[N],vis1[N],vis2[N];
int cnt,ans[N];
int main(){
scanf("%d%d%d",&n,&m,&x);
for(int i=1;i<=m;i++){
int l,r;
scanf("%d%d",&l,&r);
s[l]++,s[r+1]--;
vis1[l]=1,vis2[r]=1;
}
for(int i=1;i<=n;i++) s[i]+=s[i-1];
int i=x-1;
while(i&&s[i]>0){
if(vis1[i]) ans[++cnt]=i;
i--;
}
i=x+1;
while(i<=n&&s[i]>0){
if(vis2[i]) ans[++cnt]=i;
i++;
}
sort(ans+1,ans+cnt+1);
for(int i=1;i<=cnt;i++) cout<<ans[i]<<" ";
return 0;
}
(因为我做出来了所以建议评黄,但是真的有点水了。但是我赛时也没写出来啊。)
硬肝了 2h,因为前两天的模拟赛有一个也是关于日期的模拟,所以这道写起来稍微好一些。虽然分讨写的有点丑,但是把 long long 打开就过了。非常的开心。
存一下吧,我写的是分为:公元前,公元后的儒略历和格里高利历,然后往整的时间点跳,最后日期特别大时,4e8 年一直到 400 年这样跳(这样好统计闰年),然后就顺利的结束了。
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int Q;
ll x;
int dayy[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool pd1(int x){//公元前儒略历
x--;
if(x%4==0) return 1;
return 0;
}
bool pd2(int x){//公元后儒略历
if(x%4==0) return 1;
return 0;
}
bool pd3(int x){//格里高利历
if(x%4!=0||(x%400!=0&&x%100==0)) return 0;
return 1;
}
void solve1(){//公元前儒略历
int mon=1,y=4713;
if(x<=365){//过不完这一年
if(x<=30) printf("%lld 1 4713 BC\n",1+x);//过不完 1 月
else{
x-=30;
for(int i=2;i<=12;i++){
mon=i;
int d=dayy[i];
if(i==2) d++;
if(x-d>0) x-=d;
else break;
}
printf("%lld %d 4713 BC\n",x,mon);
}
return;
}
x-=366,y++;
x++;
for(int i=4712;i;i--){
y=i;
int d=pd1(i)?366:365;
if(x-d>0) x-=d;
else break;
}
for(int i=1;i<=12;i++){
mon=i;
int d=dayy[i];
if(i==2&&pd1(y)) d++;
if(x-d>0) x-=d;
else break;
}
printf("%lld %d %d BC\n",x,mon,y);
}
void solve2(){//公元后儒略历
x-=1721423;
if(x==0) x++;
int mon=1,y=1;
for(int i=1;i<=1582;i++){
y=i;
int d=pd2(i)?366:365;
if(x-d>0) x-=d;
else break;
}
for(int i=1;i<=12;i++){
mon=i;
int d=dayy[i];
if(i==2&&pd2(y)) d++;
if(x-d>0) x-=d;
else break;
}
printf("%lld %d %d\n",x,mon,y);
}
void solve3(){//格里高利历但是把这一年没过完
x-=2299160;
int mon=10,d=1;
if(x<=17) printf("%lld 10 1582\n",14+x);
else{
x-=17;
for(int i=11;i<=12;i++){
mon=i;
int d=dayy[i];
if(x-d>0) x-=d;
else break;
}
printf("%lld %d 1582\n",x,mon);
}
}
void solve4(){//格里高利历但是快进到 1600 年
x-=2299238;
int mon=1,y=1583;
for(int i=1583;i<=1600;i++){
y=i;
int d=365;
if(pd3(i)) d++;
if(x-d>0) x-=d;
else break;
}
for(int i=1;i<=12;i++){
mon=i;
int d=dayy[i];
if(i==2&&pd3(y)) d++;
if(x-d>0) x-=d;
else break;
}
printf("%lld %d %d\n",x,mon,y);
}
void solve5(){//格里高利历但是大跃进
x-=2305813;
ll y=1600,tot=1e6,mon=1;
for(int i=6;i;i--){
while(x-1ll*146097*tot>0){
x-=1ll*146097*tot;
y+=1ll*400*tot;
}
tot/=10;
}
while(1){
y++;
int d=365;
if(pd3(y)) d++;
if(x-d>0) x-=d;
else{
for(int i=1;i<=12;i++){
mon=i;
int p=dayy[i];
if(i==2&&d==366) p++;
if(x-p>0) x-=p;
else break;
}
break;
}
}
printf("%lld %lld %lld\n",x,mon,y);
}
int main(){
// freopen("julian3.in","r",stdin);
// freopen("ans.out","w",stdout);
scanf("%d",&Q);
while(Q--){
scanf("%lld",&x);
if(x<=1721423) solve1();
else if(x>1721423&&x<=2299160) solve2();
else if(x>2299160&&x<=2299238) solve3();
else if(x>2299238&&x<=2305813) solve4();
else solve5();
}
return 0;
}
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=106;
const int mod=1e6+7;
int n,m;
int a[N];
int f[N][N];
int main(){
// freopen("xx.in","r",stdin);
// freopen("xx.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=min(j,a[i]);k++)
f[i][j]=(f[i][j]+f[i-1][j-k])%mod;
printf("%d",f[n][m]);
return 0;
}
13.P1095 [NOIP2007 普及组] 守望者的逃离
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10;
int m,s,t;
int main(){
// freopen("xx.in","r",stdin);
// freopen("xx.out","w",stdout);
scanf("%d%d%d",&m,&s,&t);
int s1=0,s2=0;
for(int i=1;i<=t;i++){
s1+=17;
if(m>=10){
m-=10;
s2+=60;
}
else m+=4;
if(s2>s1) s1=s2;
if(s1>s){
puts("Yes");
printf("%d",i);
return 0;
}
}
printf("No\n%d",s1);
return 0;
}
本文作者:Moyyer_suiy
本文链接:https://www.cnblogs.com/Moyyer-suiy/p/18487411
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2023-10-20 CSP-S 2023 游记