[考试总结]noip模拟56
今天的题目还真的是好玩。。。
爆零 -> 高考 -> 垫底 -> 种田
爆零
题目是个原题。。。
然后我是贪心做的,其实可以动态规划。。
说一下沈队的 \(dp\),因为题解里面的 \(dp\) 太麻烦了。
规定 \(dp_x\) 为 \(x\) 的子树中至少有一个边走了一次的最小的步数。
然后转移就是
\[dp_x = \sum \min(dp_y,2 * siz_y)\\
dp_x += \max(\min(dp_y-2*siz_y),0)
\]
贪心::
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#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; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io; static const int maxn = 2e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp;
inline void add(int x,int y) {edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;}
int n,ind[maxn],d[maxn],maxdep[maxn];
int cnt[maxn],ans[maxn],fa[maxn];
class xin_data
{
public:
int x,maxdep;
xin_data(){}
xin_data(int x,int maxdep):x(x),maxdep(maxdep){}
};
void dfs1(int x,int f)
{
d[x] = d[f] + 1; maxdep[x] = d[x];
go(i,x)
{
if(y == f) continue;
dfs1(y,x); maxdep[x] = std::max(maxdep[x],maxdep[y]);
}
}
void dfs2(int x,int f)
{
std::vector < xin_data > vec; vec.clear();
go(i,x)
{
if(y == f) continue;
dfs2(y,x); vec.push_back(xin_data(y,maxdep[y]));
ans[x] += cnt[y];
}
std::sort(vec.begin(),vec.end(),[](xin_data x,xin_data y) -> bool{return x.maxdep < y.maxdep;});
try(i,0,(int)vec.size() - 1)
{
if(i and vec[i-1].maxdep - d[x] < d[x]) cnt[x]--,ans[x] += vec[i-1].maxdep - d[x];
cnt[x] += cnt[vec[i].x];
ans[x] += ans[vec[i].x];
}
}
inline short main()
{
file(a);
io >> n;
try(i,2,n)
{
io >> fa[i];
add(i,fa[i]); add(fa[i],i); ind[i] ++; ind[fa[i]] ++;
}
try(i,1,n) cnt[i] = (ind[i] == 1);
dfs1(1,0); dfs2(1,0);
cout<<ans[1]<<endl;
return 0;
}
}
signed main() {return xin::main();}
动态规划::
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#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; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io;static const int maxn = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
#define int long long
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
class xin_edge{public:int next,ver;}edge[maxn];
int head[maxn],rp;
auto add = [](int x,int y) -> void{edge[++rp].ver = y;edge[rp].next = head[x]; head[x] = rp;};
int siz[maxn],d[maxn],ind[maxn],fa[maxn],dp[maxn];
int n;
void dfs(int x)
{
siz[x] = 1;
go(i,x)
{
d[y] = d[x] + 1;
dfs(y);
siz[x] += siz[y];
}
if(ind[x] == 1 and x != 1) return dp[x] = d[x],void();
int sum = 0,minn = inf;
go(i,x)
{
sum += min(dp[y],2 * siz[y]); minn = min(minn,dp[y] - 2 * siz[y]);
}
dp[x] = sum + max(0,minn);
}
inline short main()
{
file(a);
io >> n;
try(i,2,n) io >> fa[i],add(fa[i],i),ind[fa[i]]++,ind[i]++;
dfs(1);
cout<<dp[1]<<endl;
return 0;
}
}
signed main() {return xin::main();}
高考
令 \(g_{i,j}\) 表示恰好有 \(i\) 个数字大于等于 \(j\) 的方案数,则 \(f\) 事实上就是\(g\) 的后缀和。 \(g\) 可以通过容斥计算
\[g_{i,j} = \sum_{k=i}^{n}\dbinom{k}{i}(-1)^{k-i}\dbinom{n}{k}\dbinom{m+n-1-jk}{n-1}
\]
然后
\[f_{i,j} = f_{i+1,j} + g_{i,j}
\]
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#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; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io;static const int maxn = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
#define int long long
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
const int mod = inf;
int fac[maxn],inv[maxn];
auto ksm = [](int x,int y,int ret = 1) -> int
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
};
int f[5055][5002],g[5003][5003];
auto C = [](int n,int m) -> int {if(n < m or n < 0 or m < 0) return 0; return fac[n] * inv[m] % mod * inv[n-m] % mod;};
int n,m;
int ans[maxn];
inline short main()
{
file(c);
io >> n >> m;
fac[0] = 1;
try(i,1,n+m) fac[i] = fac[i-1] * i % mod;
inv[n+m] = ksm(fac[n+m],mod-2);
throw(i,n+m-1,1) inv[i] = inv[i+1] * (i + 1) % mod; inv[0] = 1;
int fh = 1;
try(i,1,n) try(j,1,m/i)
{
fh = 1;
try(k,i,m/j) (g[i][j] += (C(k,i) * fh * C(n,k) % mod * C(n+m-1-j*k,n-1) % mod + mod) % mod) %= mod,fh = - fh;
//sb(n); jb(m);
// sb(i); sb(j); jb(g[i][j]);
}
try(j,1,m) throw(i,m/j,1) (f[i][j] = f[i+1][j] + g[i][j]) %= mod;//,cout<<f[i][j]<<endl;
try(i,1,n)
{
try(j,1,m/i) (ans[i] += f[i][j]) %= mod;
(ans[i] += ans[i-1]) %= mod;
printf("%lld\n",((ans[i] * ksm(C(n+m-1,n-1),mod-2) % mod) % mod + i) % mod);
}
return 0;
}
}
signed main() {return xin::main();}
垫底
这个题目我们将每一个点的贡献拆开。
之后分为四个部分来求:
- l
- r
- const
- l*r
然后分别用树状数组维护后缀和。
之后每次我们分别计算四个东西的贡献。
我们要用到 \(ODT\),在单调指针不到 \(r\) 的时候疯狂 \(upd\)
因为数据是随机的,所以就可以过掉了。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define int long long
#define try(i,a,b) for(register int i=a;i<=b;++i)
#define throw(i,a,b) for(register int i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#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; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io;static const int maxn = 1e6+10,two = 2e3+10,inf = 1e9+7;const ll llinf = 1e18+7;
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
const int mod = inf;
auto ksm = [](int x,int y,int ret = 1) -> int
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
};
int n,m,p;
class xin_bit
{
private:
#define low(x) ((x) & (-x))
public:
int c[maxn];
std::function<void(int x,int val)> add = [&](int x,int val) -> void {for(;x;x-=low(x)) (c[x] += val + mod) %= mod;};
std::function<int(int x)> query = [&](int x) -> int{int ret = 0;for(;x<=n;x+=low(x)) (ret += c[x] + mod) %= mod; return ret;};
}bit1,bit2,bit3,bit4;
class xin_data
{
private:
friend bool operator < (xin_data x,xin_data y)
{return x.l < y.l;}
public:
int l,r;
mutable int tim;
xin_data(int l,int r = 0,int tim = 0):l(l),r(r),tim(tim){}
};
std::set<xin_data>s;
auto split = [](int pos)
{
auto it = s.lower_bound(xin_data(pos));
if(it != s.end() and it -> l == pos) return it; it --;
register int l = it -> l,r = it -> r,tim = it -> tim;
s.erase(it); s.insert(xin_data(l,pos-1,tim));
return s.insert(xin_data(pos,r,tim)).first;
};
int l[maxn],r[maxn],ql[maxn],qr[maxn],pos[maxn],ans[maxn];
auto upd = [](int l,int r,int tim)
{
auto end = split(r + 1),now = split(l);
while(now != end)
{
register int len = (now -> r) - (now -> l) + 1,nt = now -> tim,temp = (tim - 1) * len % mod;
bit1.add(tim,temp); bit1.add(nt,-temp + mod);
bit2.add(tim,(temp + 2 * len) % mod); bit2.add(nt,len * (-1 - nt + mod) % mod);
bit3.add(tim,len * (1 - tim * tim % mod + mod) % mod); bit3.add(nt,len * (tim * nt % mod + tim - nt - 1 + mod) % mod);
bit4.add(tim,-len+mod); bit4.add(nt,len);
s.erase(now ++);
}
s.insert(xin_data(l,r,tim));
};
inline short main()
{
file(b);
io >> n >> m;
try(i,1,n) io >> l[i] >> r[i],r[i] --;
try(i,1,m) io >> ql[i] >> qr[i],pos[i] = i;
s.insert(xin_data(0,(int)1e9,0));
std::sort(pos+1,pos+m+1,[](int x,int y) -> bool{return qr[x] < qr[y];});
try(i,1,m)
{
register int now = pos[i];
// cout<<qr[now]<<endl;
while(p < qr[now]) ++p,upd(l[p],r[p],p);
register int ret,len = qr[now] - ql[now] + 1;
int inv = ksm(((len + 1) * len / 2) % mod,mod-2);
ret = bit4.query(ql[now]) * qr[now] % mod * ql[now] % mod;
// jb(ret);
(ret += bit1.query(ql[now]) * ql[now] % mod) %= mod;
(ret += bit2.query(ql[now]) * qr[now] % mod) %= mod;
(ret += bit3.query(ql[now])) %= mod;
ans[now] = ret * inv % mod;
}
try(i,1,m) printf("%lld\n",ans[i]);
return 0;
}
}
signed main() {return xin::main();}
种田
说起来还真是没脸
使用了特殊的 \(rand\) 种子。。
然后测试点分治
但是我们 \(rand\) 也是有方法的。
就是我们要注意题目当中的实数
那么我们就要考虑是负数的情况。
这样就有稳定的 \(70pts\)
然后至于 \(100pts\),只能没脸狂试。。。。
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
#define file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#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; int ak; typedef long long ll; typedef unsigned long long ull;
class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
{
register int f = 0;s = 0; register char ch = gc();
while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
}}io;
}
using namespace xin_io;static const int maxn = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
#define int long long
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
int n,ans = inf,maxx = -inf;
class xin_data
{
public:
int a,b,c;
double pai;
}d[maxn];
auto random = [](int x) -> int {return (ll)rand() * rand() % x;};
std::mt19937 rnd(clock() xor time(0));
double rd[maxn];
int cnt = 0;
inline short main()
{
file(d);
srand((unsigned)(time(0) xor clock()));
io >> n;
try(i,1,n) io >> d[i].a >> d[i].b >> d[i].c,maxx = max(maxx,max(d[i].a,d[i].b));
auto pan = []() -> bool{return clock() < 0.96 * CLOCKS_PER_SEC;};
int jsq = 0;
if(n > 2000)
{
rd[++cnt] = 5226; rd[++cnt] = 68.5792; rd[++cnt] = 15773.4; rd[++cnt] = 2548; rd[++cnt] = -9.65; rd[++cnt] = 18386;
rd[++cnt] = -1324;
// try(i,1,10) rd[++cnt] = (double)rnd() * 5000.0 / (double)rnd();
}
else
{
try(i,1,10000) rd[++cnt] = (double)rnd() * 3123.14159265358 / (double)rnd();
try(i,10001,20000) rd[++cnt] = (double)rnd() * 3.1415926535 / (double)rnd();
}
std::random_shuffle(rd+1,rd+cnt+1);
while(pan())
{
jsq ++;
jsq %= (cnt + 1);
double s = rd[jsq],t = 1;
if(random(2)) s = -s; if(random(2)) t = -t;
try(i,1,n) d[i].pai = d[i].a * s+ d[i].b * t;
// printf("%.5lf %.5lf\n",s,t);
std::sort(d+1,d+n+1,[](xin_data x,xin_data y) -> bool{return x.pai < y.pai;});
int l,r;
try(i,1,n) if(d[i].c) {l = i; break;} throw(i,n,1) if(d[i].c) {r = i;break;}
if(l xor r)
{
try(i,1,n) if(d[i].pai == d[l].pai) {l = i; break;}
throw(i,n,1) if(d[i].pai == d[r].pai) {r = i; break;}
ans = min(ans,r - l + 1);
}
else ans = 0;
// if(ans == 299993) cout<<s<<endl;
}
//if(n <= 10) {cout<<"cbx ak ioi!"<<endl; exit(0);}
if(n <= 2000) cout<<ans<<endl;
else cout<<ans - 1<<endl;
return 0;
}
}
signed main() {return xin::main();}