NOIP 模拟赛 10.21

14 篇文章 0 订阅
13 篇文章 0 订阅

传送门(MZOJ)

T1(日程表):

模拟题,直接每次模拟删除和加入就好。
注意两个点:
1.答案开 l o n g    l o n g long\;long longlong
2. v i s vis vis数组要 5 e 7 5e7 5e7

Code

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
#define rep(i,a,b) for(ll (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int maxn=3e6+10;
const int maxm=5e7+10;
ll x[maxn],ans[maxn],sum[maxn],q[maxn];
bool vis[maxm];
ll m,n,a,b,c;

template <class t> inline void read(t &x) {
	x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
	x*=f;
}

void readdata() {
	read(n),read(m),read(a),read(b),read(c);
	x[0]=0;
	rep(i,1,m) {
		x[i]=(a*x[i-1]+b)%(2*n*c);
	}
}

void work() {
	rep(i,1,m) {
		if(x[i]<(n*c)) {
			ll pos=floor(x[i]/c)+1;
			if(vis[pos]==0) {
				vis[pos]=1;
				q[i]=(q[i-1]+1)%mod;
				ans[i]=(ans[i-1]+pos)%mod;
			}
			else {
				q[i]=(q[i-1])%mod;
				ans[i]=(ans[i-1])%mod;
			}
		}
		if(x[i]>=(n*c)) {
			ll pos=floor(x[i]/c)-n+1;
			if(vis[pos]==1) {
				vis[pos]=0;
				q[i]=(q[i-1]-1)%mod;
				ans[i]=(ans[i-1]-pos)%mod;
			}
			else {
				q[i]=(q[i-1])%mod;
				ans[i]=(ans[i-1])%mod;
			}
		}
	}
	ll ans1=0,ans2=0;
	rep(i,1,m) ans1=(ans1+q[i])%mod;
	rep(i,1,m) ans2=(ans2+ans[i])%mod;
	printf("%lld %lld",ans1,ans2);
}

int main() {
	//freopen("schedule.in","r",stdin);
//	freopen("schedule.out","w",stdout);
	readdata();
	work();
	return 0;
}

T2(关联点):

倍增优化数的遍历

对于每一个节点,做出的贡献都是唯一的,则通过倍增的方式找到它做出贡献的那个点,在判断是左儿子还是右儿子就可以了

有个小优化

现将 v [ i ] v[i] v[i]减一,跳到做贡献的那个点的下方,方便判断是左儿子还是右儿子。当距离为 v [ i ] v[i] v[i]时,我们将 v [ i ] v[i] v[i]拆成二进制数,应为是要将这个点向上走 v [ i ] v[i] v[i]这么多步,则对于这个二进制数,哪一位是 1 1 1,我们就可以向上跳 2 2 2的这么多位的次方

比如7,我们就可以先跳 2 0 2^0 20,再跳 2 1 2^1 21,再跳 2 2 2^2 22

Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int maxm=1e3+10;
const int maxn=2e5+10;
int n,cnt;
int a[maxn],head[maxn],l[maxn],r[maxn],dep[maxn],f[maxn][21],son[maxn];

template <class t> inline void read(t &x) {
	x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
	x*=f;
}

struct node{
	int v,nex;
}e[maxn];

void add(int u,int v) {
	e[++cnt].v=v;
	e[cnt].nex=head[u];
	head[u]=cnt;
}

void readdata() {
	read(n);
	rep(i,1,n) read(a[i]);
	rep(i,1,n) {
		int x,y;
		read(x),read(y);
		if(x!=0) {add(i,x);son[x]=1;}
		if(y!=0) {add(i,y);son[y]=0;}
	}
}

void dfs_first(int u,int fa,int deep) {
	dep[u]=deep;
	f[u][0]=fa;
	rep(i,0,19) f[u][i+1]=f[f[u][i]][i];
	for(int i=head[u];i;i=e[i].nex) {
		int v=e[i].v;
		if(v==fa) continue;
		dfs_first(v,u,deep+1);
	}
}

void work() {
	memset(l,false,sizeof(l));
	memset(r,false,sizeof(r));
	dfs_first(1,0,1);
	rep(u,1,n) {
		int x=u;a[x]--;
		rep(i,0,19) {
			if((1<<i)&a[u]) x=f[x][i];
		}
		if(son[x]) l[f[x][0]]++;
		else r[f[x][0]]++;
	}
	rep(i,1,n) {
		printf("%d %d\n",l[i],r[i]);
	}
}

int main() {
//	freopen("node.in","r",stdin);
//	freopen("node.out","w",stdout);
	readdata();
	work();
	return 0;
}

T3(送分题)

转移方程
f [ u ] [ o ] = m a x ( f [ u ] [ o ] g [ i ] + f [ v ] [ j ] ) f[u][o] =max(f[u][o]g[i] +f[v][j]) f[u][o]=max(f[u][o]g[i]+f[v][j])

f [ i ] [ k ] f[i][k] f[i][k]表示以 i i i为根,选择的点距离它的距离至少为 k k k的最优解

Code

#include<bits/stdc++.h>
#define inf 100000000
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int maxn=1e5+10;
const int maxm=1e3+10;
int n,K,cnt;
int a[maxn],head[maxn];
int f[maxn][110],g[maxn];

template <class t> inline void read(t &x) {
	x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
	x*=f;
}

struct node{
	int v,nex;
}e[maxn<<1];

void add(int u,int v) {
	e[++cnt].v=v;
	e[cnt].nex=head[u];
	head[u]=cnt;
}

void readdata() {
	read(n);read(K);
	rep(i,1,n) read(a[i]);
	rep(i,1,n-1) {
		int x,y;
		read(x),read(y);
		add(x,y);add(y,x);
	}
}

void dfs(int u,int fa) {
	f[u][0]=a[u];
	for(int i=head[u];i;i=e[i].nex) {
		int v=e[i].v;
		if(v==fa) continue;
		dfs(v,u);
		memcpy(g,f[u],sizeof(f[u]));
		for (int a = 0;a <=K;++a) {
			for (int b = K - a;b <= K;++b) {
				f[u][min(a,b+1)] = max(f[u][min(a,b+1)],g[a]+f[v][b]);
			}
		}
	}
}

void work() {
	int ans=-inf;
	dfs(1,0);
	rep(i,1,K) ans=max(ans,f[1][i]);
	printf("%d\n",ans);
}

int main() {
	freopen("score.in","r",stdin);
	//freopen("score.out","w",stdout);
	readdata();
	work();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个参选手有相同的机会和条件进行竞争。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值