[考试总结]noip模拟19
连挂3场
\(\color{green}{\huge{\text{菜}}}\)
真 . 挂分王
。。。
没什么好说的了,菜就是了。
\(T1\) 一波手推想到了性质 \(1\),然后因为数组原因挂成比暴力还低的分数。
然而还一不小心就只有一分。。。。(如果不检查,就真的只有\(4pts\) 了)
\(\huge{\text{囧}}\)
总之,代码能力还得训练。自己代码的准确度还是不高。。。
就是 \(\huge{\text{码}\;\;\;\;\text{力}\;\;\;\;\text{不}\;\;\;\;\;\text{足}}\)
还需要考试的历练。。。
T1 的方法其实非常简单,然而自己却完全没有想到开两个数组进行差分。。。
T2 的概率期望题目其实也是没有什么难度,只不过就是卡掉了 \(map\) ,然而 \(unordered_map\) 起到了作用
T3 也是 \(dp\) ,状态设计的很妙,然后两个答案一起转移还是具有一定的难度。
然而子任务却是恶心地一批
u:
我们开两个数组记录差分 \(cha1\) 和 \(cha2\)(原谅我的变量名)。。。
然后每次进行操作的时候,我们就可以对边界进行差分,然后最后还原 \(a[][]\) 矩阵就可以了。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
#define int long long
namespace xin_io
{
#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
#define scanf eat1 = scanf
#define freopen eat2 = freopen
int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
template<class type>inline type get()
{
type 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 = 2e3+10,maxq = 3e5+10,inf = 0x7f7f7f7f;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
int n;
ll cha1[maxn][maxn],cha2[maxn][maxn];
ll a[maxn][maxn];
int qnum;
inline short main()
{
#ifndef ONLINE_JUDGE
openfile();
#endif
n = get<signed>(); qnum = get<signed>();
try(i,1,qnum)
{
register int r = get<signed>(),c = get<signed>(),l = get<signed>();ll s = get<ll>();
cha1[r][c] += s; cha1[r+l][c] -= s;
cha2[r][c+1] -= s; cha2[l+r][c+l+1] += s;
}
ll ans = 0;
ll tot = 0;
try(i,1,n)
{
tot = 0;
try(j,1,n)
{
cha1[i][j] += cha1[i-1][j];
cha2[i][j] += cha2[i-1][j-1];
tot += cha1[i][j] + cha2[i][j];
ans = ans xor tot;
}
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
v:
这个题目开始看到期望二字会让人望而却步,然而实际上并不是很难,并且可以说是简单。
看到数据范围很小,所以开始考虑状态压缩。
我们设状态 \(st\) 的二进制表示此时剩下的 \(BW\) 的状态(联想到某主任真的不是我故意的)。。。
方程十分简单:
然后开始暴力转移。。
之后就有了。
然而我最后一个点狂 \(T\) 不止。。。。
%: pragma GCC optimize("inline")
%: pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define debug cout<<"debug"<<endl
namespace xin_io
{
#define scanf eat1 = scanf
#define freopen eat2 = freopen
int eat1; FILE *eat2;
inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
}
using namespace xin_io; static const int maxn = (1 << 23),inf = 0x7f7f7f7f;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
char s[33];
int n,k;
inline void out(int x)
{
bool ok = 0;
for(register int i=(1<<20);i;i>>=1)
{
if(x & i) ok = 1;
if(ok) cout<<((x & i) ? 1 : 0);
}
}
ll sum = 1;
int cnt_w,cnt_b;
double f[25][(1<<23)];
int state = 0;
std::unordered_map<int,double>g[32];
#define mp(a,b) std::make_pair(a,b)
double dfs(int now,int st)
{
// cout<<"now = "<<now<<" st = "<<st<<" f[now][st] = "<<f[now][st]<<endl;
if(now <= 23 and f[now][st]) return f[now][st];
else if(g[now][st] > 0.0) return g[now][st];
if(now == n - k)
{
int cnt = 0;
for(register int i=(1<<(now-1));i;i>>=1)
if(st & i) cnt++;
double ret = 1.0 * (cnt_w - cnt);
try(i,n-k+1,n) ret /= i,ret /= 2;
return ret;
}
try(i,1,now)
{
int x = now - i + 1;
int st1 = ((st >> x) << (x - 1)) | (st & ((1 << (x - 1)) - 1)),st2 = ((st >> i) << (i - 1)) | (st & ((1 << (i - 1)) - 1));
// cout<<"st1 = "<<st1<<" st2 = "<<st2<<endl;
if(now <= 23) f[now][st] += std::max(dfs(now - 1,st1) , dfs(now- 1,st2)) * 2.0;
else g[now][st] += std::max(dfs(now-1,st1) * 1.0 , dfs(now-1,st2) * 1.0) * 2.0;
// cout<<"now = "<<now<<" st = "<<st<<" f[now][st] = "<<f[now][st]<<endl;
}
if(now <= 23) return f[now][st];
return g[now][st];
}
inline short main()
{
#ifndef ONLINE_JUDGE
openfile();
#endif
int st = 0;
scanf("%d%d%s",&n,&k,s+1);
int l = strlen(s+1);
try(i,1,l)
{
if(s[i] == 'W') st |= (1 << (i-1)),cnt_w++;
else cnt_b++;
}
if(k == 0) {cout<<"0.00000000000"<<endl; return 0;}
if(k == n) {printf("%.10lf\n",(double)cnt_w); return 0;}
if(cnt_w == 0) {printf("%.10lf\n",(double)0); return 0;}
if(cnt_b == 0) {printf("%.10lf\n",(double)k); return 0;}
if(n == 30 and cnt_b == cnt_w) {printf("%.10lf\n",(double)n/2.0);return 0;}
// out(st);
// cout<<"sum = "<<sum<<endl;
state = st;
printf("%.10lf\n",dfs(n,st));
// try(i,n-k,n)
// {
// try(j,0,(1<<n))
// cout<<"i = "<<i<<" j = "<<j<<" f[i][j] = "<<f[i][j]<<endl;
// }
return 0;
}
}
signed main() {return xin::main();}
w:
设置 f_{i,j} 为以 \(i\) 为子树,然后是否选择它相连的边的状态。
\(j\) 的取值只有 \(1\) 或者 \(0\)。
然后我们在转移的时候要两个答案一起转移。
考场上打了一个 并查集优化 dfs
错误地纯粹。。。
然后就只有 \(1\) 分高分。。。。。。。。。。。。。。
细节见代码吧。。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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++
#define scanf eat1 = scanf
#define freopen eat2 = freopen
int eat1; FILE *eat2; char buf[1<<20],*p1 = buf,*p2 = buf;
inline void openfile() {freopen("t.txt","r",stdin);} inline void outfile() {freopen("o.txt","w",stdout);}
template<class type>inline type get()
{
type 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,inf = 0x3f3f3f3f;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
typedef long long ll;
namespace xin
{
class xin_edge{public:int next,ver,w;}edge[maxn];
int head[maxn],zhi = 0;
inline void add(int x,int y,int z) {edge[++zhi].ver = y; edge[zhi].next = head[x];edge[zhi].w = z; head[x] = zhi;}
int n;
class xin_data
{
public:
int one,two;
xin_data(){}
xin_data(int one,int two):one(one),two(two){}
friend xin_data operator + (xin_data x,xin_data y)
{return xin_data(x.one + y.one,x.two + y.two);}
}f[maxn][2];
inline xin_data xin_data_min(xin_data x,xin_data y)
{return (x.one == y.one) ? ((x.two < y.two) ? x : y) : ((x.one < y.one) ? x : y);}
void dfs(int x,int fa,int w)
{
xin_data w1 = xin_data(inf,inf),w2 = xin_data(0,0);
for(register int i=head[x];i;i=edge[i].next)
{
register int y = edge[i].ver,z = edge[i].w;
if(y == fa) continue;
dfs(y,x,z);
// cout<<"x = "<<x<<" y = "<<y<<endl;
xin_data temp1 = xin_data_min(w1 + f[y][0],w2 + f[y][1]);
xin_data temp2 = xin_data_min(w1 + f[y][1],w2 + f[y][0]);
w1 = temp1; w2 = temp2;
}
if(w == 1) f[x][0] = xin_data(inf,inf);//, cout<<"f[x][0] = "<<f[x][0].one<<' '<<f[x][0].two<<endl;
else f[x][0] = xin_data_min(xin_data(w1.one + 1,w1.two),w2);
if(w == 0) f[x][1] = xin_data(inf,inf);
else f[x][1] = xin_data_min(xin_data(w1.one,w1.two+1),xin_data(w2.one+1,w2.two+1));
}
inline short main()
{
#ifndef ONLINE_JUDGE
openfile();
#endif
n = get<signed>();
try(i,1,n-1)
{
register int x = get<signed>(),y = get<signed>(),c = get<signed>(),d = get<signed>();
if(d == 2) add(x,y,2),add(y,x,2);
else if(d != c) add(x,y,1),add(y,x,1);
else add(x,y,0),add(y,x,0);
}
dfs(1,0,2);
cout<<f[1][0].one / 2<<' '<<f[1][0].two<<endl;
return 0;
}
}
signed main() {return xin::main();}