版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)
Directory is in hand, the world I have
Thinking process
- 2:30拿题,开头映入眼帘的是
额,要凉凉啊。 - 前半个小时,看题,写方程,搞算法。
- 先去搞了 ,毕竟写过,就照着思路写了,最后样例一直输出 68,很无语,后来发现是状态转移方程打错了,赶紧改过来,此时 3:20,看到 大佬已经写完,并且上去评测了,结果 !收下小弟的膝盖。
- 后过头来搞 ,很明显是一道树形Dp,然而太长时间没写,忘了套路了,磕磕绊绊,后被 提醒“你枚举两种情况”,猛的想到可以分这个节点选还是不选,然后判断合法,ok,有了思路,然后想着 一下,加上数据范围,很明显 算法,就过了。
- 实在不会啊,设状态设成 表示状态为 的方案数,结果不会转移,也没想出他有后效性,就 gg 了,然后此时还有半个小时比赛结束,于是乎不想写了,直接交上去,评测 ,看到三位强者全是 的我瞬间感觉, 可能要被踩爆了,要垫底了,算了,交过了,就不说这事了,去问了 的写法,然后给 口胡一段二分图,额,比赛就结束了。
- 成绩? 吧,觉得大家没发挥好。 问这次题这么简单,下次要不要难些啊,我。。(冒汗)。
- 最后吐槽一下出题人取名字真随便。
a
title
analysis
写完之后,就可以说:这就是一道树形Dp入门题了。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
template<typename T>inline void write(T x)
{
if (!x) { putchar('0'); return ; }
if (x<0) putchar('-'), x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) putchar(ch[num--]);
}
int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int f[maxn][2];
inline void dfs(int x,int fa)
{
f[x][1]=1,f[x][0]=0;
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==fa) continue;
dfs(y,x);
f[x][0]+=max(f[y][1],f[y][0]);
f[x][1]+=f[y][0];
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
int n;
read(n);
for (int i=1,x,y; i<=n-1; ++i) read(x),read(y),add(x,y),add(y,x);
dfs(1,0);
write(max(f[1][1],f[1][0]));
return 0;
}
b
title
analysis
某谷上好像有这道题,环形石子合并。
如果写过的话,务必
了这道题来压惊!
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
template<typename T>inline void write(T x)
{
if (!x) { putchar('0'); return ; }
if (x<0) putchar('-'), x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) putchar(ch[num--]);
}
int v[maxn],sum[maxn],f[maxn][maxn];
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
int n;
read(n);
for (int i=1; i<=n; ++i) read(v[i]),v[n+i]=v[i];
for (int i=1; i<=(n<<1); ++i) sum[i]=sum[i-1]+v[i];//处理前缀和
for (int len=2; len<=n; ++len)
for (int l=1; l+len-1<=(n<<1); ++l)
{
int r=l+len-1;
for (int k=l; k+1<=r; ++k) f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]);//状态转移,模拟合并
f[l][r]+=sum[r]-sum[l-1];//最后加上这个区间的能量
}
int ans=0;
for (int i=1; i<=n; ++i) ans=max(ans,f[i][i+n-1]);
write(ans);
return 0;
}
c
title
analysis
考场上被告知正解为状压Dp,然而设状态没搞成,就 gg 了。后来被
大佬严格证明一维状态有后效性,可能会将错误状态强行转成正确转态来统计,是错误的。嗯,又在大佬的帮助下,A 掉此题。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxs=1<<16,maxn=17,maxh=25e3+10;
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
template<typename T>inline void write(T x)
{
if (!x) { putchar('0'); return ; }
if (x<0) putchar('-'), x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) putchar(ch[num--]);
}
ll f[maxs][maxn],h[maxh];
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
int n,k;read(n);read(k);
for (int i=1; i<=n; ++i) read(h[i]);
for (int i=1; i<=n; ++i) f[1<<i-1][i]=1;//在第i位放上i的方案数为1
for (int s=1; s<=(1<<n)-1; ++s)//枚举所有可能的状态
for (int i=1; i<=n; ++i)//枚举前一个填进去的数字
for (int j=1; j<=n; ++j)//枚举现在要填进去的数字
{
if (s&(1<<j-1)) continue;//如果他已被填进去
if (abs(h[i]-h[j])>k) f[s|(1<<j-1)][j]+=f[s][i];//由前一个状态,填进前一个数字转移过来
}
ll ans=0;
for (int i=1; i<=n; ++i) ans+=f[(1<<n)-1][i];
write(ans);
return 0;
}