[考试总结]noip模拟67(多校)
博客真的快要咕爆炸了。。。
看到自己上一次的博客还在 \(60\),然后非常佛。。。
今天的题目完全搞不出来,然后就写一写博客吧。。
咕了太多,那就先补一补多校联考的吧。。。
数据恢复
这个题目我们考虑贪心。
这个贪心的策略就是 \(v_i = \frac{a_i}{b_i}\),我们要选择的就是这个 \(v_i\) 最小的就行。
那么我们考虑使用 \(multiset\) 维护
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define gec() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream &operator >> (type &s)
{
s = 0; register bool f = 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+10;
#define int long long
namespace xin
{
class xin_data
{
public:
int a,b;
double c;
}d[maxn];
int f[maxn],fa[maxn];
inline int find(int x) {return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);}
int n;
bool vis[maxn];
std::multiset<std::pair<double,int>>s;
int ans = 0;
inline void merge(int x,int y)
{
ans += d[y].b * d[x].a;
d[y].b += d[x].b; d[x].b = 0;
d[y].a += d[x].a; d[x].a = 0;
d[y].c = (double)d[y].a / (double)d[y].b;
fa[find(x)] = y;
}
inline short main()
{
file(data);
io >> n;
try(i,2,n) io >> f[i];
try(i,1,n)
{
io >> d[i].a >> d[i].b; d[i].c = (double)d[i].a / (double)d[i].b;
fa[i] = i; s.insert(std::make_pair(d[i].c,i)); vis[i] = 1;
}
while(!s.empty())
{
auto top = s.begin();
int x = top -> second,y;
s.erase(top); vis[x] = 0;
if(!f[x]) continue;
if(vis[y = find(f[x])])
{
d[y].c = (double)d[y].a / (double)d[y].b;
s.erase(s.find(std::make_pair(d[y].c,y)));
merge(x,y);
s.insert(std::make_pair(d[y].c,y));
}
else merge(x,find(y));
}
cout<<ans<<endl;
return 0;
}
}
signed main() {return xin::main();}
下落的小球
这个题目考虑一个合并的操作。
我们将每个操作向上挂到树上,然后我们在之上计算答案。
对于一个相对顺序确定的长度为 \(x\) 的序列和一个长度是 \(y\) 的序列合并的方案数就是 \(\dbinom{x+y}{x}\)
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define gec() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream &operator >> (type &s)
{
s = 0; register bool f = 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+10;
#define int long long
namespace xin
{
const int mod = 1e9+7;
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 fac[maxn],inv[maxn],fa[maxn],a[maxn];
int ans1[maxn],ans2[maxn],siz[maxn],r[maxn];
int he1[maxn],he2[maxn];
int n;
inline int C(int n,int m) {return fac[n] * inv[m] % mod * inv[n-m] % mod;}
inline int ksm(int x,int y,int ret = 1)
{
while(y)
{
if(y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret;
}
void dfs(int x)
{
siz[x] = ans1[x] = ans2[x] = 1;
go(i,x)
{
dfs(y);
siz[x] += siz[y]; a[x] += a[y];
he1[x] += r[y]; he2[x] += siz[y];
(ans1[x] *= ans1[y] * C(he1[x],r[y]) % mod) %= mod;
(ans2[x] *= ans2[y] * C(he2[x],siz[y]) % mod) %= mod;
// sb(ans1[x]); jb(ans2[x]);
}
r[x] = a[x] - siz[x];
// sb(x); sb(a[x]); jb(siz[x]);
}
inline short main()
{
file(ball);
io >> n;
try(i,2,n) io >> fa[i],add(fa[i],i);
try(i,1,n) io >> a[i];//,jb(a[i]);
fac[0] = inv[0] = 1;
try(i,1,n) fac[i] = fac[i-1] * i % mod;
inv[n] = ksm(fac[n],mod-2);
throw(i,n-1,1) inv[i] = inv[i+1] * (i + 1) % mod;
dfs(1);
cout<<ans1[1] * ans2[1] % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}
消失的运算符
这个在考场上是写了一个表达式求值,然后 \(\color{purple}{RE}\) 了。
是因为没清空。。。
然后就有 \(40pts\) 大分。。
这个在考场上似乎是最高的,然后因为挂了,所以只有 \(20pts\) 了,然而还是最高的
#include<bits/stdc++.h>
using std::cout; using std::endl;
#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(x) FILE *FI = freopen(#x".in","r",stdin); FI = freopen(#x".out","w",stdout);
#define sb(x) cout<<#x" = "<<x<<' '
#define jb(x) cout<<#x" = "<<x<<endl
#define debug cout<<"debug"<<endl
#define gec() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
#define gc() getchar()
#define scanf ak = scanf
char buf[1<<20],*p1 = buf,*p2 = buf; using ll = long long; using ull = unsigned long long; int ak;
class xin_stream{public:template<typename type>xin_stream &operator >> (type &s)
{
s = 0; register bool f = 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+10;
#define int long long
namespace xin
{
const int mod = 1e9+7;
std::stack<char> st;
char ys[maxn];
int top=0,jsq=0;
int yunsuan[maxn];
int level(char a)
{
if(a == '(' or a== ')' )
return -1;
if(a=='+' or a=='-')
return 1;
if(a=='*' or a=='/')
return 2;
return 0;
}
inline int calc(std::string &a)
{
jsq = top = 0; while(!st.empty()) st.pop();
int l=a.size();
for(int i=0;i<l-1;++i)
{
if(a[i] >= '0' and a[i] <= '9' )
{
ys[++top]=a[i];
ys[++top]=' ';
continue;
}
if(st.empty() and ( a[i] == '+' or a[i] == '-' or a[i] == '*' or a[i] =='/'))
{
st.push( a[i] );
continue;
}
if(a[i] == '(')
{
st.push( a[i] );
continue;
}
if(a[i] == ')')
{
while(st.top() != '(')
{
ys[++top]=st.top();
st.pop();
}
st.pop();
continue;
}
if(( a[i] == '+' or a[i] == '-' or a[i] == '*') and ( st.empty() == false))
{
if( level ( a[i] ) > level( st.top() ) )
{
st.push( a[i] );
continue;
}
if(level(a[i]) <= level(st.top()))
{
while(!st.empty() and level (a[i])<= level(st.top()))
{
ys[++top]=st.top();
st.pop();
}
st.push(a[i]);
continue;
}
}
}
while(st.empty() == false)
{
ys[++top]=st.top();
st.pop();
}
int p=1,x=0;
while(p<=top)
{
if(ys[p] == '+') yunsuan[--jsq] += yunsuan[jsq+1];
else if(ys[p] == '*') (yunsuan[--jsq] *= yunsuan[jsq+1]) %= mod;
else
{
x=0;
while(ys[p]!=' ')
x=x*10+ys[p++]-'0';
yunsuan[++jsq]=x;
}
p++;
}
return yunsuan[jsq];
}
int a[maxn],zhi = 0;
int n,k;
std::string s;
int pos[maxn],cnt = 0;
int ans = 0;
inline int check()
{
std::string temp = s; temp += '@';
try(i,1,zhi) temp[pos[a[i]]] = '+';
for(auto &ch : temp) if(ch == '-') ch = '*';
// cout<<temp<<endl; jb(calc(temp));
return calc(temp) % mod;
}
void dfs()
{
if(zhi == k)
{
ans += check(); ans %= mod;
return ;
}
try(i,a[zhi]+1,cnt)
{
a[++zhi] = i;
dfs();
zhi --;
}
}
inline short main()
{
freopen("operator.in","r",stdin); freopen("operator.out","w",stdout);
scanf("%lld%lld",&n,&k);
std::cin >> s; int l = s.size() - 1;
try(i,0,l)
if(s[i] == '-') pos[++cnt] = i;
dfs();
cout<<ans % mod<<endl;
return 0;
}
}
signed main() {return xin::main();}