某九校联考模拟试题D1

T1:餐馆

题目描述:

共有 n 种食材,一份食材 i 需要花 ti 小时不间断地进行播种,施肥,直至收获。当然,一份食材 i 是可以直接卖掉得到 wi 块钱的。招牌菜共有 m 种,一份招牌菜 i 需要消耗一定的食材,花 Ti 小时不间断地来烹饪,叫卖,并最终卖出得到 Wi 块钱。整个季度换算下来一共有 Tmax 小时可供你使用,铜企鹅需要在这期间赚到最多的钱,这样他才有足够多的钱来 steam 剁手,或者氪金手游

输入格式:

第一行一个整数 T,表示数据组数。

令 i 表示为当前数据内行数。

第一行三个整数 n, m, Tmax,含义如题所示。第二行至第 n + 1 行,每行两个整数 ti−1, wi−1,含义如题所示。

第 n + 2 行至第 n + m + 1 行,每行两个整数 Ti−n−1, Wi−n−2,含义如题所示。

第 n + m + 2 行至第 n + 2m + 1 行,每行 n 个整数,第 j 个数 dj 表示招牌菜 i − n − m − 1 需要 dj 个食材。

输出格式:

对于每组数据,输出一行一个整数,表示你所能赚到的最多的钱。

样例:

略~

数据范围:

对于 100% 的数据,保证 0 < ti, Ti ≤ Tmax ≤ 5000, 0 ≤ wi, Wi ≤ 109,每份招牌菜使用的食材的个数总数不超过 10。

完全背包水题。scanf读入超时卡成50分= =

T2:烯烃

题目描述:

给你一棵树,一些边有标记,对于每条有标记的边,在树中找到包含这条边的一条最长链,并输出长度。

输入格式:

第一行一个整数 id 表示测试点的编号。多组数据,第二行一个整数 T 表示数据组数。对于每组数据,第一行两个整数 n, m 表示节点的个数,和被标记的边的个数。我们规定 1 是根,第二行 n − 1 个整数给出 2 ∼ n 父亲的编号,保证f ai < i。第三行 m 个整数范围在 [2, n] 表示哪个点的父边被标记。

输出格式:

对于每组数据输出一行 m 个整数,必须与输入的边顺序一致,给出的是在这条边必选的情况下树中最长链的长度。

样例输入:

0
1
10 3
1 2 3 1 4 6 7 3 8
10 7 9

样例输出:

8 8 6

数据范围:

n,m<=1e5,T<=100

裸题。求每条边所在最长链的长度。详见直径求法,最后再记一个从上面下来的最长长度,记得更新在dfs前。

坑点:最后一个输出没有空格,m=0不输出回车= =

然而考试的时候并不知道这种解法,菊花10分。

#include<bits/stdc++.h>
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
const int Maxn=100005;
vector<int>G[Maxn];
#define to G[x][i]
int f1[Maxn],f2[Maxn],up[Maxn];
int prt[Maxn];
void dfs1(int x){
	f1[x]=f2[x]=up[x]=0;
	for(int i=0;i<G[x].size();++i)if(to^prt[x]){
		dfs1(to);
		int tmp=f1[to]+1;
		if(tmp>f1[x])f2[x]=f1[x],f1[x]=tmp;
		else f2[x]=max(f2[x],tmp);
	}
}
void dfs2(int x){
	for(int i=0;i<G[x].size();++i)if(to^prt[x]){
		if(f1[to]+1==f1[x]){
			up[to]=max(up[x]+1,f2[x]+1);
		}else {
			up[to]=max(up[x]+1,f1[x]+1);
		}
		dfs2(to);
	}
}
int main(){
//	freopen("olefin.in","r",stdin);
//	freopen("olefin.out","w",stdout);
	get();int T=get();
	while(T--){
		int n=get(),m=get();
		for(int i=1;i<=n;++i)G[i].clear();
		for(int i=2;i<=n;++i){
			prt[i]=get();
			G[prt[i]].push_back(i);
		}
		dfs1(1);dfs2(1);
		for(int i=1;i<=m;++i){
			int x=get();
			cout<<f1[x]+up[x];
			if(i!=m)cout<<' ';
		}
		if(m)cout<<'\n';
	}
	return 0;
}

T3:三米诺

题目太难copy,自行百度= =

数据范围:10^40000。

解法很诡,打表高斯消元找规律?这道题对我的贡献仅仅是复习一下高斯消元,了解十进制快速幂而已(还有OEIS)

简要提一下十进制快速幂:

例如我们要求a^233666=a^200000*a^30000*a^3000*a^600*a^60*a^6

我们维护一个a^10n底数,每次做的时候ans*=base^num[i]。

#include<bits/stdc++.h>
using namespace std;
#define p 998244353
const int Maxn=40005;
struct Matrix{
	long long mat[15][15];
	void init(int N){
		memset(mat,0,sizeof(mat));
		if(N)for(int i=1;i<=6;++i)mat[i][i]=1;
	}
};
Matrix mult(Matrix a,Matrix b,int I,int J,int K){
	Matrix c;c.init(0);
	for(int i=1;i<=I;++i)
		for(int j=1;j<=J;++j)
			for(int k=1;k<=K;++k)
				(c.mat[i][j]+=a.mat[i][k]*b.mat[k][j])%=p;
	return c;
}
Matrix quick(Matrix a,int b){
	Matrix ret=a,ans;ans.init(1);
	for(;b;b>>=1){
		if(b&1)ans=mult(ans,ret,6,6,6);
		ret=mult(ret,ret,6,6,6);
	}
	return ans;
}
Matrix _10system(Matrix a,int *b,int len){
	Matrix ret=a,ans;ans.init(1);
	for(int i=1;i<=len;++i){
		ans=mult(ans,quick(ret,b[i]),6,6,6);
		ret=quick(ret,10);
	}
	return ans;
}
char x[Maxn];
int len,s[Maxn];
int f[7]={0,1,3,10,23,62,170};
int main(){
//	freopen("tromino.in","r",stdin);
//	freopen("tromino.out","w",stdout);
	scanf("%s",x+1);
	len=strlen(x+1);
	if(len==1&&x[1]<='6'){cout<<f[x[1]-'0']<<'\n';return 0;}
	for(int i=1;i<=len;++i)s[len-i+1]=x[i]-'0';
	s[1]-=6;
	for(int i=1;i<len;++i)if(s[i]<0)s[i]+=10,--s[i+1];
	for(;s[len]<=0;--len);
//	for(int i=len;i>=1;--i)cout<<s[i];
	Matrix ans;ans.init(0);
	for(int i=1;i<=6;++i)ans.mat[1][i]=f[i];
	Matrix ret;ret.init(0);
	ret.mat[2][1]=ret.mat[3][2]=ret.mat[4][3]=ret.mat[5][4]=ret.mat[6][5]=1;
	ret.mat[1][6]=p-1;ret.mat[3][6]=1;ret.mat[4][6]=6;ret.mat[5][6]=2;ret.mat[6][6]=1;
	
	ret=_10system(ret,s,len);
	ans=mult(ans,ret,1,6,6);
	cout<<ans.mat[1][6]<<'\n';
	return 0;
}

有很没骨气的补了一份代码上去。

最后得分:50+10+10=70

2道签到题。。。整个人的飘了o(╥﹏╥)o

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值