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