T1
T2
T3
以上是题面
考试的时候先看的第三题,感觉可以用模拟退火乱搞出来,但是后面发现这不是一个状压DP,所以打了一个比较玄学的dfs(给每条边赋了一个错误率),然后只骗到27分
第二题是想出了一个DP方程:f[i][j]是指i个点高度等于j的方案数,有方程
f
[
i
]
[
j
]
=
∑
k
=
1
,
z
=
1
k
=
i
−
2
,
z
=
j
−
1
(
f
[
k
]
[
j
−
1
]
×
f
[
i
−
1
−
k
]
[
z
]
)
+
∑
k
=
1
,
z
=
1
k
=
i
−
2
,
z
=
j
−
1
(
f
[
k
]
[
z
]
×
f
[
i
−
1
−
k
]
[
j
−
1
]
)
f[i][j]=\sum_{k=1,z=1}^{k=i-2,z=j-1}(f[k][j-1]\times f[i-1-k][z])+\sum_{k=1,z=1}^{k=i-2,z=j-1}(f[k][z]\times f[i-1-k][j-1])
f[i][j]=∑k=1,z=1k=i−2,z=j−1(f[k][j−1]×f[i−1−k][z])+∑k=1,z=1k=i−2,z=j−1(f[k][z]×f[i−1−k][j−1]),过了小样例但没过大样例
第一题一眼就看出来是和noip货币系统极像,但是就是被那个2e9吓到了,又加上电脑爆炸和蹲厕所,就没有来得及打代码
按道理说正常情况下100分以上是可以得到的,但是尴尬的是这次用cena交代码,还没来得及保存到收集目录下电脑就被教师机控制了,所以最后只交了第三题的代码,还是自己太弱啊(下次考试一定先用dos关掉教师机嘿嘿嘿嘿嘿)
接下来进入正题
T1
嘿嘿嘿,2e9吓死人,但其实本题的答案范围是不会超过 250 2 {250}^{2} 2502的(详情请见最大不可表数),这也就意味着可以用刷表的方式来解决本题
设f[i]指块数为3的包装可不可以被凑出来,则有方程 f [ i ] = f [ i ] ∣ f [ j ] , 1 < = k < = i f[i]=f[i]|f[j],1<=k<=i f[i]=f[i]∣f[j],1<=k<=i,n方刷一遍表在O(N)枚举一下就可以了
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
#define ll long long
int n;
const int maxn=15;
const int maxw=256*256+100;
int a[maxn];
bool f[maxw];
template<typename T>void read(T &x){
x=0;register char r=getchar();T neg=1;
while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
x*=neg;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif // ONLINE_JUDGE
clean(f,false),clean(a,0);
read(n);
loop(i,1,n)read(a[i]),f[a[i]]=true;
loop(i,1,maxw)if(f[i]==true)
loop(j,1,n)
if(a[j]+i<=maxw)f[a[j]+i]=true;
anti_loop(i,maxw,1)if(f[i]==false){
if(i<=maxw-100)printf("%d\n",i);
else printf("%d\n",0);
exit(0);
}
printf("%d\n",0);
return 0;
}
T2
这道题的状态比较有趣
其实上面的状态设计已经差不多接近比较正的解了,但由于“高度等于h”这个条件太“苛刻”了(呵呵),我们就可以改进一下,用f[i][j]表示i个节点高度小于等于j的方案数,于是有
f
[
i
]
[
j
]
=
∑
k
=
1
k
=
i
−
2
f
[
k
]
[
j
−
1
]
×
f
[
i
−
1
−
k
]
[
j
−
1
]
f[i][j]=\sum_{k=1}^{k=i-2} f[k][j-1]\times f[i-1-k][j-1]
f[i][j]=∑k=1k=i−2f[k][j−1]×f[i−1−k][j−1](确实简洁了不少),当然,边界就是
f
[
1
]
[
k
]
=
1
(
1
<
=
k
<
=
n
)
f[1][k]=1(1<=k<=n)
f[1][k]=1(1<=k<=n),答案就是
f
[
n
]
[
k
]
−
f
[
n
−
1
]
[
k
]
f[n][k]-f[n-1][k]
f[n][k]−f[n−1][k]
注意: 这里要求要对9901取模,因此可能f[n][k]-f[n-1][k]<0,所以在输的时候就要对这个值加一个9901再取模以防为负数
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
#define ll long long
template<typename T>void read(T &x){
x=0;char r=getchar();T neg=1;
while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
x*=neg;
}
const int maxn=200+10;
const int maxk=110;
const int mod=9901;
int n,k;
int f[maxn][maxk];
int main(){
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif // ONLINE_JUDGE
clean(f,0);
read(n),read(k);
loop(i,1,k)f[1][i]=1;
for(int i=3;i<=n;i+=2){
loop(j,1,k+2){
for(int z=1;z<=i-2;z+=2){
f[i][j]+=f[z][j-1]*f[i-1-z][j-1];
f[i][j]%=mod;
}
}
}
printf("%d\n",(f[n][k]-f[n][k-1]+mod)%mod);
return 0;
}
T3
这题当时根本就没往动归方向去想,以至于看到题解的时候有点懵逼
假定有两个人a和b,f[i][j]表示a到达i,b到达j,则有
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
]
[
k
]
+
1
,
f
[
i
]
[
j
]
)
f[i][j]=max(f[i][k]+1,f[i][j])
f[i][j]=max(f[i][k]+1,f[i][j])由于f[i][j]=f[j][i],则没有必要更新f[j][i],到时候直接赋值就好
注意这里我们强制j>i,j>k则i,j不可重复且j,k不可重复,为了保证i,k不重复,我们在代码中加一个判定:当且仅当f[i][k]!=0时才用其更新,这样就保证了
1.f[i][i]不合法
2.任意一个状态f[i][j],i!=j中不会包含有f[i][i],1<=i<=n的情况
这样就保证了最后答案中路径不会有交集
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
#define ll long long
const int maxn=100+10,mod=18960421;
bool G[maxn][maxn];
int f[110][110];
char name[20];
map<int,int>m;
int S;
int n,v;
inline int hash(char *r){
int len=strlen(r);
int res=0;
for(int i=0;i<len;++i)res=(res*100+r[i]-'A'+10)%mod;
return res;
}
template<typename T>void read(T &x){
x=0;char r=getchar();T neg=1;
while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
x*=neg;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif // ONLINE_JUDGE
read(n),read(v);
for(register int i=1;i<=n;++i){
scanf("%s",name);if(i==1)S=hash(name);
m[hash(name)]=i;
}
for(int i=1;i<=v;++i){
int xi,yi;
scanf("%s",name);xi=hash(name);scanf("%s",name);yi=hash(name);
G[m[xi]][m[yi]]=G[m[yi]][m[xi]]=true;
}
f[1][1]=1;
loop(i,1,n-1){
loop(j,i+1,n){
loop(k,1,j-1){
if (G[j][k]&&f[i][k])
f[i][j]=max(f[i][j],f[i][k]+1);
f[j][i]=f[i][j];
}
}
}
int _maxx=1;
loop(i,1,n){
if(G[i][n])_maxx=max(_maxx,f[i][n]);
}
printf("%d\n",_maxx);
return 0;
}
不念过去,不惧将来,如此安好