C - Madoka and Formal Statement
首先a[i]>b[i]是不可以的,再有就是a[i]!=b[i]且b[i]>b[i+1]+1也是不可以的,因为a[i]最多增到a[i+1]+1。
重要的是证明:假设j=i+1,如果a[i]!=b[i],a[i]>a[j],那么a[j]要增长到a[i]可以变化才可以,只要没有不符合条件的情况,a[j]只要增到b[j]了那么a[i]也一定会增到b[i]。我们可以在j和i之间连一条j->i的有向边,表示j<i,那么按这种规则连下去一定不是环,所以总是可以的
Codeforces Round #818 (Div. 2) A~E - 知乎 (zhihu.com)
ll t,n,a[200005],b[200005];
int main(){
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int j=1;j<=n;j++) cin>>b[j];
ll flag=1;
for(int i=1;i<=n;i++){
ll j=(i+1)%n;
if(j==0) j=n;
if(a[i]>b[i]){flag=0;break;}
if(a[i]!=b[i]&&b[i]>b[j]+1){flag=0;break;}
}
if(flag) printf("yEs\n");
else printf("no\n");
}
return 0;
}
D - Madoka and The Corruption Scheme
根据贪心策略,在k=0~n的过程中优先填较小的数,然后就可以推出n=6左右的情况,然后把k=1~n做差就可以发现,每个差值都是一个组合数(但是没发现是组合数啊啊啊啊啊!),然后这题就做完了,,还是对组合数不够敏感,对前缀和还挺敏感的一直在想如何用前缀和做,,,
Codeforces Round #818 (Div. 2) A~E - 知乎 (zhihu.com)
ll fac[100005];
ll C(ll a,ll b){
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
ll n,k,a[100005];
int main(){
fac[0]=1;
for(ll i=1;i<=100000;i++) fac[i]=fac[i-1]*i%mod;
scanf("%lld%lld",&n,&k);
if(k>n) k=n;
a[0]=1;
for(int i=1;i<=k;i++){
a[i]=(a[i-1]+C(n,i))%mod;
}
printf("%lld\n",a[k]);
return 0;
}
D-一人行者_牛客练习赛102 (nowcoder.com) 换根dp,前后缀积
忘了不开这道题了,一下午没了,,,
f当前子树包含的所有连通块个数,g当前子树包含当前节点的连通块个数,当前节点的父亲去除当前节点后的连通块个数,删去当前节点与父亲的边的与父亲那颗树的连通块个数,看了几个题解,还不如一个代码来的清晰,,,为了防止除0用了前后缀积,感觉并不像是换根dp,只是一个比较难的树形dp,硬要说换根的话就是反过来求去除v之后的u有多少联通子集用到了,有些需要注意到了
29. 牛客-一人行者 - Theophania - 博客园 (cnblogs.com)
ll n,m,k,a[500005],b[500005];
vector<ll>h[500005];
ll fa[500005],f[500005],g[500005];
// f当前子树包含的所有连通块个数
// g当前子树包含当前节点的连通块个数
void dfs(ll u,ll fat){
if(fat) h[u].erase(find(h[u].begin(),h[u].end(),fat));
fa[u]=fat;
g[u]=1;
for(auto v:h[u]){
dfs(v,u);
g[u]=g[u]*(g[v]+1)%mod;
f[u]=(f[u]+f[v])%mod;
}
f[u]=(f[u]+g[u])%mod;
}
ll df[500005];//当前节点的父亲去除当前节点后的连通块个数
ll sf[500005];//删去当前节点与父亲的边的与父亲那颗树的连通块个数
void dfs2(ll u){
ll len=h[u].size();
vector<ll>pre(len+1,0),suf(len+2,0);
for(int i=0;i<=len;i++) pre[i]=(i?pre[i-1]*(g[h[u][i-1]]+1)%mod:1);
for(int i=len+1;i>=1;i--) suf[i]=(i>len?1:suf[i+1]*(g[h[u][i-1]]+1)%mod);
//cout<<"sss "<<u<<endl;
ll tmp=df[u]+1;
for(int i=1;i<=len;i++){
ll v=h[u][i-1];
df[v]=(tmp*pre[i-1]%mod)*suf[i+1]%mod;
sf[v]=((df[v]+sf[u]+f[u]-g[u]-f[v])%mod+mod)%mod;
//u去除v后的连通块个数加上u的父亲不包含u的联通子集个数再加上u子树中不包含u的子集个数
//再减去v子树所有的联通子集个数就是去除了v点的联通子集个数
// cout<<"sss ssaaa "<<v<<" "<<u<<endl;
dfs2(v);
}
}
int main(){
scanf("%lld",&n);
for(int i=1;i<n;i++){
scanf("%lld%lld",&a[i],&b[i]);
h[a[i]].push_back(b[i]);
h[b[i]].push_back(a[i]);
}
dfs(1,0);
// cout<<" sss"<<endl;
dfs2(1);
//cout<<" sss"<<endl;
for(int i=1;i<n;i++){
if(fa[a[i]]==b[i]) printf("%lld %lld\n",f[a[i]],sf[a[i]]);
else printf("%lld %lld\n",sf[b[i]],f[b[i]]);
}
return 0;
}