曾记否,到中流击水,浪遏飞舟。|

Moyyer_suiy

园龄:2年8个月粉丝:4关注:18

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;
}

5.P2280 [HNOI2003] 激光炸弹

赤裸裸的二维前缀和板子,呃呃之前怎么没有提交过。/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;
}

6.P1908 逆序对

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;
}

7.P4343 [SHOI2015] 自动刷题机

有个小朋友一开始忘了二分答案的板子应该怎么写,于是很错误的二分并陷入了死循环((

这么水的二分答案也能绿。是为了照顾像我这样不会写板子的人吗?感觉思维量还不如前面两个小橙题。

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。先咕一下。


9.P9868 [NOIP2023] 词典

又一道意难平。至今找不到去年源文件,突然无法确定我 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;
	}
}

10.P9166 [省选联考 2023] 火车站

继续继续,又是意难平。赛时只会模拟,大概算法没学透彻,思考也不到位吧。好像是爆零了。看着讨论区里“这题送分有啥意义吗”,陷入了思考。有意义啊,我不在这吗。

然后想了十分钟顺利的写完了。没有刷新就跳出来的 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; 
} 

(因为我做出来了所以建议评黄,但是真的有点水了。但是我赛时也没写出来啊。)


11.P7075 [CSP-S2020] 儒略日

硬肝了 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;
}

12.P1077 [NOIP2012 普及组] 摆花

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 中国大陆许可协议进行许可。

posted @   Moyyer_suiy  阅读(9)  评论(0编辑  收藏  举报
历史上的今天:
2023-10-20 CSP-S 2023 游记
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起