[考试总结]20210524
我好菜啊
这次考试真的是很有必要,也是找到了很多的弱点,也发现自己真的是很菜,还有很多要提升的地方,很多的知识点还需要巩固,做题之前也一定要把给出的样例搞懂再想着去打,不然打的越多,越浪费时间。
对于这一次考试,发现自己的心态还是出现了一些问题,在发现自己的T1
的样例怎么也是过不去的时候,心态就已经出现了很大的问题,在转头放弃T1
的时候自己心中还是一直在想着T1
,以至于在打T2
和T3
的时候也没有打对,所以说心态还是很重要的。
T1:
对于他们在一个点的转移,他们会选择自己可以到达的并且可以玩完的地点进行转移!!!
这就是我sb的地方
对于状态的转移与初末状态也是非常好找,我们不妨设 \(f_{i,j}\) 为这个小朋友在 \(i\) 位置,花费了 \(j\) 时间所能获得的最大开心度期望值,所以最终我们想要的状态就是 \(f_{n,k}\),完全可以考虑搜索,就从 \(f_{n,k}\) 进入搜索,之后在边界进行赋值,只有算出 \(f_{n,k}\) 的值就是最终的答案。
搜索 \(code :\)
#include<cmath>
#include<queue>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define m(c,num) memset(c,num,sizeof c)
#define INF 0x7f7f7f7f
#define debug cout<<"debug"<<endl
namespace xin_io
{
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf;
FILE* a14;
inline void openfile() {a14 = freopen("data.txt","r",stdin);}
inline void outfile() {a14 = freopen("o.txt","w",stdout);}
inline int get()
{
int s = 0,f = 1;
register char ch = gc();
while(!isdigit(ch))
{
if(ch == '-') f = -1;
ch = gc();
}
while(isdigit(ch))
{
s = s * 10 + ch - '0';
ch = gc();
}
return s * f;
}
}
using namespace xin_io;
static const int maxn = 1e2 + 10;
static const int maxm = 1e6 + 10;
namespace xin
{
int n,m,k;
int c[maxn],h1[maxn],h2[maxn];
class xin_edge
{
public:
int next,w,ver;
}edge[maxm];
int head[maxm],zhi = 0;
inline void add(int x,int y,int z)
{
edge[++zhi].ver = y; edge[zhi].w = z;
edge[zhi].next = head[x]; head[x] = zhi;
}
double f[maxn][maxn * 6];
double ans1 = 0.0,ans2 = 0.0;
bool pan = 0;
double dfs(int tim,int x)
{
// cout<<"time = "<<tim<<" loc = "<<x<<" f[x][tim] = "<<f[x][tim]<<endl;
if(f[x][tim]) return f[x][tim];
int cnt = 0;
for(register int i=head[x];i;i=edge[i].next)
if(tim - c[edge[i].ver] - edge[i].w >= 0)
cnt++;
if(!pan) f[x][tim] += h1[x];
else f[x][tim] += h2[x];
if(!cnt) return f[x][tim];
for(register int i=head[x];i;i=edge[i].next)
{
register int y = edge[i].ver,z = edge[i].w;
if(tim - z - c[y] >= 0)
f[x][tim] += dfs(tim - z - c[y],y) / ( 1.0 * cnt);
}
return f[x][tim];
}
inline short main()
{
#ifndef ONLINE_JUDGE
openfile();
#endif
n = get(); m = get(); k = get();
for(register int i=1;i<=n;++i) c[i] = get(),h1[i] = get(),h2[i] = get();
for(register int i=1;i<=m;++i)
{
register int x = get(),y = get(),z = get();
add(x,y,z); add(y,x,z);
}
for(register int i=1;i<=n;++i)
ans1 += dfs(k - c[i],i);//,ans2 += sdf(c[i],i);
memset(f,0.0,sizeof f);
pan = 1;
for(register int i=1;i<=n;++i)
ans2 += dfs(k - c[i],i);
// for(register int i=1;i<=n;++i)
// for(register int j=1;j<=k;++j)
// cout<<"i = "<<i<<" j = "<<j<<" f[i][j] = "<<f[i][j]<<endl;
printf("%.5lf %0.5lf\n",ans1 / n,ans2 / n);
return 0;
}
}
signed main() {return xin::main();}
当然一般的线性递推也是可以的
线性递推 \(code:\)
#include<cmath>
#include<queue>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define m(c,num) memset(c,num,sizeof c)
#define INF 0x7f7f7f7f
#define debug cout<<"debug"<<endl
namespace xin_io
{
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf;
inline void openfile() {freopen("t.txt","r",stdin);}
inline void outfile() {freopen("o.txt","w",stdout);}
inline int get()
{
int s = 0,f = 1;
register char ch = gc();
while(!isdigit(ch))
{
if(ch == '-') f = -1;
ch = gc();
}
while(isdigit(ch))
{
s = s * 10 + ch - '0';
ch = gc();
}
return s * f;
}
}
using namespace xin_io;
static const int maxn = 1e6 + 10;
namespace xin
{
int n,m,k;
int h1[maxn],h2[maxn],c[maxn];
class xin_edge
{
public:
int ver,next;
int w;
}edge[maxn<<1];
int head[maxn],zhi = 0;
inline void add(int x,int y,int z)
{
edge[++zhi].ver = y; edge[zhi].w = z;
edge[zhi].next = head[x]; head[x] = zhi;
}
double ans1 = 0.0;
double ans2 = 0.0;
void dfs(int ms,int x,int fa,double p,int now)
{
int cnt = 0;
for(register int i=head[x];i;i=edge[i].next)
{
register int y = edge[i].ver,z = edge[i].w;
if(now + z + c[y] <= ms)
cnt++;
}
double pnow = p;
ans1 += pnow * h1[x];
ans2 += pnow * h2[x];
if(cnt) pnow = p / (1.0 * cnt);
// cout<<"x = "<<x<<" time = "<<now<<" more = "<<pnow * h1[x]<<" p = "<<pnow<<endl;
for(register int i=head[x];i;i=edge[i].next)
{
register int y = edge[i].ver,z = edge[i].w;
if(now + z + c[y] <= k) dfs(ms,y,x,pnow,now + z + c[y]);
}
}
double f[101][481],g[101][481];
inline short main()
{
#ifndef ONLINE_JUDGE
openfile();
#endif
n = get(); m = get(); k = get();
for(register int i=1;i<=n;++i)
c[i] = get(),h1[i] = get(),h2[i] = get();
for(register int i=1;i<=m;++i)
{
register int x = get(),y = get(),z = get();
add(x,y,z); add(y,x,z);
}
for(register int j=k;j;--j)
{
for(register int i=1;i<=n;++i)
{
f[i][j] = h1[i]; g[i][j] = h2[i];
int cnt = 0;
for(register int x=head[i];x;x=edge[x].next)
if(edge[x].w + j + c[edge[x].ver] <= k)
cnt++;
for(register int x=head[i];x;x=edge[x].next)
if(edge[x].w + c[edge[x].ver] + j <= k)
{
f[i][j] += f[edge[x].ver][j + edge[x].w + c[edge[x].ver]] / (1.0 * cnt);
g[i][j] += g[edge[x].ver][j + edge[x].w + c[edge[x].ver]] / (1.0 * cnt);
}
}
}
for(register int i=1;i<=n;++i)
{
ans1 += f[i][c[i]] / (1.0 * n);
ans2 += g[i][c[i]] / (1.0 * n);
}
printf("%.5lf %.5lf\n",ans1,ans2);
return 0;
}
}
signed main() {return xin::main();}
T2:
这题目一看就是高斯消元,(还不是自己之前做过开关问题。。。)
\(x_i\) 表示第 \(i\) 个点是否打开,1为开,0为关,所以方程就很好列出。
但是,这里就存在一个很致命的问题:
方程的解似乎是不唯一的
所以到最后就会出现不定方程,之后暴搜每一个自由元的取值反正范围小,随便搜呗
所以 \(code:\)
#include<cmath>
#include<queue>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define m(c,num) memset(c,num,sizeof c)
#define INF 0x7f7f7f7f
#define debug cout<<"debug"<<endl
namespace xin_io
{
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
char buf[1<<20],*p1 = buf,*p2 = buf;
inline void openfile() {freopen("data.txt","r",stdin);}
inline void outfile() {freopen("o.txt","w",stdout);}
inline int get()
{
int s = 0,f = 1;
register char ch = gc();
while(!isdigit(ch))
{
if(ch == '-') f = -1;
ch = gc();
}
while(isdigit(ch))
{
s = s * 10 + ch - '0';
ch = gc();
}
return s * f;
}
}
using namespace xin_io;
#define moy(c) cout<<sizeof(c) / ( 1<< 20)<<" MB"<<endl;
static const int maxn = 1e2+10;
namespace xin
{
int n;
int a[maxn][maxn];
vector < int > link[maxn];
int b[maxn];
int ans = 0x7f7f7f7f;
inline void gs()
{
for(register int i=1;i<=n;++i)
{
int r = i;
for(register int j=i;j<=n;++j)
if(a[j][i]) {r = j; break;}
// if(!a[r][i]) continue;
if(r != i)
for(register int j=i;j<=n+1;++j)
swap(a[i][j],a[r][j]);
for(register int j=i+1;j<=n;++j)
if(a[j][i])
for(register int k=n+1;k>=i;--k)
a[j][k] ^= a[i][k];
}
}
void dfs(int x,int now)
{
if(now >= ans)return;
if(x == 0) {ans = now;return;}
if(a[x][x])
{
b[x] = a[x][n+1];
for(register int j=x+1;j<=n;++j)
b[x] ^= b[j] * a[x][j];
dfs(x-1,now+b[x]);
}
else
{
b[x] = 0; dfs(x-1,now); b[x] = 1; dfs(x-1,now+1);
}
}
inline short main()
{
#ifndef ONLINE_JUDGE
openfile();
#endif
while(1)
{
n = get();
if(!n) return 0;
for(register int i=1;i<=n-1;++i)
{
register int x = get(),y = get();
link[x].push_back(y);
link[y].push_back(x);
}
for(register int i=1;i<=n;++i)
{
a[i][i] = 1; a[i][n+1] = 1;
for(register int j=0;j<link[i].size();++j)
a[i][link[i][j]] = 1;
}
// for(register int i=1;i<=n;++i,putchar('\n'))
// for(register int j=1;j<=n+1;++j)
// cout<<a[i][j]<<' ' ;cout<<endl;
gs();
ans = 0x7f7f7f7f;
// for(register int i=1;i<=n;++i,putchar('\n'))
// for(register int j=1;j<=n+1;++j)
// cout<<a[i][j]<<' ';
dfs(n,0);
printf("%d\n",ans);
memset(a,0,sizeof a); memset(b,0,sizeof b);
for(register int i=1;i<=n;++i) link[i].clear();
}
return 0;
}
}
signed main() {return xin::main();}
T3:
这个题就比较魔性了,状压是我没有想到的
f[i][j][k][l]表示前i位,用了j次道路,i的前K位(包括i)状态的奇偶性,此时考虑i和i-K+l的连边
如果这条边连,f[i][j+1][k^(1<<K)^(1<<l)]+=f[i][j][k][l];
如果不连,f[i][j][k][l+1]+=f[i][j][k][l],
如果l==K,f[i+1][j][k>>1][0]+=f[i][j][k][l];
特殊判断i-K+l<=0的状态不合法
这个说实话以现在的水平,完全想不到,所以还需要加强
code就不贴出来了,方程明白了自然code就出来了。