10.1 考试总结

10.1 考试总结

得分情况

  • 0pts+50pts+0pts+0pts

时间分配(大概)

  • 2.5hour(T1)+0.5hour(造小数据实验)+1hour(T2)

错点:

  • 没开longlong+数组开小了(T2)
    --> 改正后95pts
  • 题意理解出错+代码能力弱+细节处理不当
    --> 能力得分应该是40 ~ 70pts
  • 时间分配,T3/T4 没时间看,T1浪费太长时间
    -->重新尝试做题顺序(先看完所有的在做抉择,但是每道都要试试) \({\color{white}试试就逝世}\)

题目分析

\({\color{black}P7075 [CSP-S2020] 儒略日}\)

考场思路

  • 直接分类讨论+取模优化,理论能过大部分点,没调出来

正解思路

  • 加一个预处理处理出N天内的年月日变化,优化时间复杂度,降低代码书写难度,所以不用分讨。其他都一样,本质上是道模拟题吧。
PS:

25-26行原来我写的是


		if(d[i]>md(y[i],m[i])) ++m[i],d[i]-=md(y[i],m[i]);
		if(m[i]>12) ++y[i],m[i]-=12;

WA了
但正解是

		if(d[i]>md(y[i],m[i])) ++m[i],d[i]=1;
		if(m[i]>12) ++y[i],m[i]=1;

感觉效果一样的,不知道为什么

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return s*f;
}
const int N=146097;
int n,t;
int y[N],m[N],d[N];//年月日
inline int md(int y,int m){//格里高利历y年m月的天数
	if(m==2) return y%4?28:y%100?29:y%400?28:29;
	return (m==4||m==6||m==9||m==11)?30:31;
}
signed main(){
	//freopen("julian3.in","r",stdin);
	//freopen("julian.out","w",stdout);
	m[0]=d[0]=1;
	for(int i=1;i<N;i++){//预处理
		d[i]=d[i-1]+1;
		m[i]=m[i-1];
		y[i]=y[i-1];
		if(d[i]>md(y[i],m[i])) ++m[i],d[i]=1;
		if(m[i]>12) ++y[i],m[i]=1;
	}
	n=read();
	for(int i=1;i<=n;i++){
		int x=read();
		if(x>2299160){
			x-=2159351;
			t=x/N*400+1200;
			x%=N;
		}else{
			t=x/1461*4-4712;
			x%=1461;
		}
		if(t+y[x]>0)printf("%lld %lld %lld\n",d[x],m[x],t+y[x]);
		else printf("%lld %lld %lld BC\n",d[x],m[x],1-t-y[x]);
	}
	return 0;
}

\({\color{black}P7076 [CSP-S2020] 动物园}\)

考场思路

  • 找到给的数的二进制中每个1的位置(我太菜了,只会用lowbit),去查询有哪几种饲料未买(规则中有的)即可。

正解思路

TJ:
  • 先计算出所有已有的动物编号中,哪些位至少存在一次,显然用|运算就行了。

  • 对于每个要求,如果第 \(p_i\) 位是存在的,那这种饲料就肯定有了。反之这种饲料是一定没有的,也就是说这一位一定不能为 1。

  • 除去一定不能为 1 的位,剩下 t 个位可能为 1,那总动物数就能达到\(2^t\) ,减去已经有的 n 个动物,所以答案是 \(2^t-n\)

其实跟我思路一样,考场以为没开longlong和数组开小了挂了50分。

code:

#include<bits/stdc++.h>
#define int long long 
using namespace std;
inline int read() {
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){s=s*10+ch-'0';ch=getchar();}
	return s*f;
}
const int N=4e7+5;
int n,m,c,k;
int a[N],b[N],f[N],ans;
int pos[N],vis[N];
int lg[N];
int lowbit(int x){
	return x&-x;
}
int logg(int x){
	if(x==1) return 1;
	return logg(x/2)+1;
}
int ksm(int x,int k){
	int res=1;
	while(k){
		if(k&1) res=res*x;
		x=x*x;
		k>>=1;
	}
	return res;
}
signed main(){
	n=read(),m=read(),c=read(),k=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		pos[x]=y;
		f[x]=-1;
	}
	for(int i=1;i<=n;i++){
		int x=a[i];
		while(x){
			int y=lowbit(x);
			int l=logg(y)-1;
			if(l>k) break;
			x-=y;
			if(pos[l]) vis[pos[l]]=1,f[l]=1;
//			cout<<x<<' '<<"?\n";
		}
	}
	for(int i=0;i<=k;i++)
		if(f[i]==-1) ans++;
	if(k-ans==64){
		if(n==0) puts("18446744073709551616");
        else cout<<-n;
		return 0;
	}
	cout<<ksm(2,k-ans)-n;
	return 0;
}
/*
对于一开始给定的宠物,计算出需要哪些饲料(即哪些规则被使用)
对于没有被使用的规则,考虑有那些数字会触发,用总共的减去即可
*/

\({\color{black}P7077 [CSP-S2020] 函数调用}\)

考场思路

  • 无(没看)

正解思路

  • 如果不看第三个操作,我们发现这道题是很容易实现的。那么很自然的就想到用函数建一个DAG,直接用拓扑排序将其的拓扑序搞出来。
  • 知道了拓扑序有什么用呢?就可以递推出每个函数等价的执行次数,然后就完成了……
PS:

拓扑排序加动态规划完全不会怎么做,只能先看一遍题解写法再写了。

code:

#include<bits/stdc++.h>
#define int long long 
using namespace std;
inline int read() {
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){s=s*10+ch-'0';ch=getchar();}
	return s*f;
}
const int N=1e5+5,mod=998244353;
int n,m;
int a[N],du[N],op[N];
int b[N],c[N],t[N],d[N],f[N];
vector<int> v[N],ve,topo;
void topsort(){
	queue<int> q;
	for(int i=0;i<=m;i++)
		if(du[i]==0) q.push(i);
	while(!q.empty()){
		int x=q.front();q.pop();
		ve.push_back(x);
		for(int i=0;i<t[x];i++){
			int y=v[x][i];
			if(--du[y]==0) q.push(y);
		}
	}
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	m=read();
	for(int i=1;i<=m;i++){
		op[i]=read();
		if(op[i]==1) b[i]=read(),c[i]=read();
		else if(op[i]==2) c[i]=read();
		else {
			t[i]=read();
			for(int j=1;j<=t[i];j++){
				int x=read();
				v[i].push_back(x);
				du[x]++;
			}
		}
	}
	int q=read();
	t[0]=q;
	while(q--){
		int x=read();
		v[0].push_back(x);
		du[x]++;
	}
	topsort();
	int len=ve.size();
	for(int i=len-1;i>=0;i--){
		int u=ve[i];
		if(op[u]==1) d[u]=1;
		else if(op[u]==2) d[u]=c[u];
		else {
			d[u]=1;
			for(int j=0;j<t[u];j++)
				d[u]=d[u]*d[v[u][j]]%mod;
		}
	}
	for(int i=1;i<=n;i++) a[i]=a[i]*d[0]%mod;
	f[0]=1;
	for(int i=0;i<len;i++){
		int u=ve[i];
		long long tmp=1;
		for(int j=t[u]-1;j>=0;j--){
			int y=v[u][j];
			f[y]=(f[y]+tmp*f[u])%mod;
    		tmp=tmp*d[y]%mod;	
		}
		if(op[u]==1)
			a[b[u]]=(a[b[u]]+c[u]*f[u]%mod)%mod;
	}
	for(int i=1;i<=n;i++) cout<<a[i]<<' ';
	return 0;
}

\({\color{black}P7078 [CSP-S2020] 贪吃蛇}\)

考场思路

  • 无(没看)

正解思路

  • 每次对于最大的蛇来说,有两种选择——吃或不吃,因为每只蛇都很聪明且他们希望在自己不被吃的前提下在决斗中尽可能多吃别的蛇,所以开始分类讨论
    1. 当前吃了之后还是最大——没影响,一定吃
    2. 当前吃了之后不是最大
      (1) 当前吃了过后不是最小,考虑到次大的如果选择吃,那么吃完后一定比他更小,所以直接吃,把问题抛给次大值,递归下去即可。
      (2) 当前吃了过后是最小,那么需要考虑次大值是否会吃,仍然是递归下去。
  • 可以看出这个递归没有分支,那么终点就是如果只剩自己一人,那么一定吃,如果自己会死,那么不吃
  • 用两个队列优化即可

code

#include<bits/stdc++.h>
#define PII pair<int,int> 
#define mk make_pair
using namespace std;
inline int read() {
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){s=s*10+ch-'0';ch=getchar();}
	return s*f;
}
const int N=1e6+5,mod=998244353;
int T,n,m,ans;
int a[N],du[N],op[N];
deque<PII> q1,q2,q;
void solve(){
	q1.clear(),q2.clear(),q.clear();
	
	for(int i=1;i<=n;i++) q1.push_back(mk(a[i],i));
	while(true){
		if(q1.size()+q2.size()==2){
			cout<<"1\n";
			return ;
		}
		PII st=q1.front();
		q1.pop_front();
		PII ed=q1.back();
		if(!q2.empty() && q2.back()>ed){
			ed=q2.back();
			q2.pop_back();
		}else q1.pop_back();
		PII tmp=mk(ed.first-st.first,ed.second);
		if(q1.front()<tmp) q2.push_front(tmp);//直接吃
		else {
			q1.push_front(tmp);
			break;
		}
	}
	while(!q1.empty() && !q2.empty()){
		if(q1.front()<q2.front()){
			q.push_back(q1.front());
			q1.pop_front();
		}else {
			q.push_back(q2.front());
			q2.pop_front();
		}
	}
	while(!q1.empty()){
		q.push_back(q1.front());
		q1.pop_front();
	}
	while(!q2.empty()){
		q.push_back(q2.front());
		q2.pop_front();
	}
	int now=q.size(),cnt=0;//cnt表示吃的次数,如果是奇数,那么不吃,否则能活,就吃
	while(q.size()>1){
		PII st=q.front(),ed=q.back();
		q.pop_front(),q.pop_back();
		cnt++;
		PII tmp=mk(ed.first-st.first,ed.second);
		if(q.front()<tmp || q.size()==0) break;
		else q.push_front(tmp);
	} 
	cout<<now+cnt%2<<'\n';
	return ;
}
signed main(){
	T=read();
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	T--;
	solve(); 
	while(T--){
		int k=read();
		for(int i=1;i<=k;i++){
			int x=read(),y=read();
			a[x]=y;
		}
		solve();
	}
	return 0;
}

总结

  • 代码能力弱
  • 考场时间分布不优
  • 细节问题
posted @ 2025-10-03 18:43  Austin0928  阅读(19)  评论(0)    收藏  举报