NOIP 模拟赛 10.21

传送门(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
#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
#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
#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;
}

你可能感兴趣的:(noip,动态规划,树上操作)