[G-Magic Spells_"蔚来杯"2022牛客暑期多校训练营9 (nowcoder.com) 马拉车](ac.nowcoder.com/acm/contest… "G-Magic Spells_"蔚来杯"2022牛客暑期多校训练营9 (nowcoder.com) 马拉车")
马拉车的性质:在更新mx也就是i + p[i] > mx的情况下会遍历到所有不同的回文串,所以可以根据这个性质来o(n)找出所有的回文串并且哈希出来进行统计
这个题总共加起来已经耗了一天的时间了,最大的收获就是上面的性质,其次就是自己的sb,2id-i写成了2id-1,然后就检查了n个小时的错误,,,又一次暴露了自己写代码的不仔细,,,
Fighting Tournament
写B的时候太急了没看出B真正的思路就开始乱写,导致C没时间写了,真是大失误,
C题一看就直接离线处理了,可以发现轮到力量为n的队员之后,这个队员就一直在赢了,所以其实最多也就是跑力量为n的队员的坐标再-1次,那就模拟跑一遍顺便更新答案,对于轮数大于坐标减1的我们就直接在最后一轮算出来就行
ll t,n,q,sum[200005],ans[200005];
struct Node{
ll id,val;
}a[200005];
struct node{
ll id,aid,rou;
bool operator<(const node &o)const{
return rou<o.rou;
}
};
vector<node>v[200005];
ll b[200005];
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n+10;i++) b[i]=0,sum[i]=0,v[i].clear();
ll ma=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i].val),a[i].id=i;
if(a[i].val==n) ma=i;
b[i]=a[i].val;
}
for(int i=1;i<=q;i++){
ll x,y,z;
scanf("%lld%lld",&x,&y);
z=y;
if(z>=ma) z=ma-1;
v[z].push_back(node{i,x,y});
}
if(b[1]==n){
for(int i=0;i<v[0].size();i++){
if(b[v[0][i].aid]<n) ans[v[0][i].id]=0;
else ans[v[0][i].id]=v[0][i].rou;
}
}
else{
ll l=1,r=2;
for(int i=1;i<ma;i++){
if(b[l]>b[r]){
sum[l]++;
r=max(r,l)+1;
}
else{
sum[r]++;
l=max(r,l)+1;
}
//if(t==0) cout<<l<<" lr "<<r<<endl;
for(int j=0;j<v[i].size();j++){
if(b[v[i][j].aid]<n){
ans[v[i][j].id]=sum[v[i][j].aid];
}
else{
ll res=max(0LL,v[i][j].rou-ma+1);
//if(t==0)cout<<"res "<<res<<endl;
ans[v[i][j].id]=sum[v[i][j].aid]+res;
}
}
}
}
for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
}
return 0;
}
[B-Two Frogs_"蔚来杯"2022牛客暑期多校训练营9 (nowcoder.com) dp](ac.nowcoder.com/acm/contest… "B-Two Frogs_"蔚来杯"2022牛客暑期多校训练营9 (nowcoder.com) dp")
这个题不明白为什么老是超时,但把i和j循环的顺序换过来就不超时了,好奇葩,,,dp[i][j]表示走了j步到i的概率,假设dp[i][j]已经知道,那么dp[i+1][j+1]----dp[i+a[i]][j+1]就都可以算出来,即dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j]*(1/a[i])),但是从1加到a[i]太慢了,所以差分就可以顺势的想出来了,之后在统计答案这题就完了
int main(){
scanf("%lld",&n);
for(int i=1;i<n;i++) scanf("%lld",&a[i]),inv[i]=getinv(a[i]);
dp[1][0]=1;
dp[2][0]=-1;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
dp[i][j]=(dp[i-1][j]+dp[i][j])%mod;
dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j]*inv[i]%mod)%mod;
dp[i+a[i]+1][j+1]=(dp[i+a[i]+1][j+1]-dp[i][j]*inv[i]%mod)%mod;
}
}
ll ans=0;
for(int i=1;i<n;i++)
if(dp[n][i]) ans=(ans+dp[n][i]*dp[n][i]%mod)%mod;
printf("%lld\n",ans);
return 0;
}
[J-Jellyfish and its dream_"蔚来杯"2022牛客暑期多校训练营(加赛) (nowcoder.com)](ac.nowcoder.com/acm/contest… "J-Jellyfish and its dream_"蔚来杯"2022牛客暑期多校训练营(加赛) (nowcoder.com)")
想到差分了,但是思考的方向错了,该死啊,,设b[i]为差分数组,可以发现(2,1)也就是b[i]=2,b[i+1]=1,那么就可以转化为(0,0),(1,1)也可以变成(2,0),(0,1)可以变为(1,0),那么可以通过(2,1)将差分数组都变为0,可以发现只要1的个数不小于2的个数总是可以将差分数组变为0的
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
ll a[N];
ll b[N];
ll n,t;
int main(){
cin>>t;
while(t--){
cin>>n;
for(ll i=1;i<=n;i++) cin>>a[i];
b[1]=(a[1]-a[n]+3)%3;
ll z=0;
z+=(b[1]==0);
for(ll i=2;i<=n;i++) b[i]=(a[i]-a[i-1]+3)%3,z+=(b[i]==0);
if(z==n){printf("Yes\n");continue;}
ll one=0,two=0;
for(int i=1;i<=n;i++){
if(b[i]==1) one++;
else if(b[i]==2) two++;
}
if(one>=two) printf("Yes\n");
else printf("No\n");
}
return 0;
}
[H-Here is an Easy Problem of Zero-chan_"蔚来杯"2022牛客暑期多校训练营(加赛) (nowcoder.com) dfs,求后缀0的方法](ac.nowcoder.com/acm/contest… "H-Here is an Easy Problem of Zero-chan_"蔚来杯"2022牛客暑期多校训练营(加赛) (nowcoder.com) dfs,求后缀0的方法")
先说如何统计后缀0,把一个有后缀0的数拆成多个2和多个5相乘,可以发现后缀0的个数等于min(2的个数,5的个数),所以我们设five[i],two[i]为i中5的个数和2的个数
求x与所有数的lca,这些lca其实都是x点到根节点1路径上的点,只是每个点的次幂不同,这个也很好统计,比如说要求x的这些lca,x与x的lca是x,x与自己孩子的lca也是x,所以x的次幂就是siz[x],在网上去找他的父亲f[x],x与f[x]的lca是f[x],x与x兄弟的lca也是f[x],所以f[x]的次幂就是siz[f[x]]-siz[x]因为siz[x]是x的孩子们,x与孩子的lca是x本身,所以要减去;以此类推就行;但是这样从下往上好像并没有什么办法可以优化时间,但是反着来从上往下就只需要一遍dfs就够了,一遍就可以处理出所有点的值来,点u后缀0的个数也就等于min(siz[u]*two[u]+tw,siz[u]*five[u]+fi),tw和fi是从根节点1一直累加过来的
ll n,q,siz[100005],five[100005],two[100005],dep[100005];
ll head[300005],cnt;
ll ans[100005];
struct Edge{
ll from,to,next;
}edge[300005];
void addedge(ll from,ll to){
edge[++cnt].from=from;
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void dfs1(ll u,ll fa){
dep[u]=dep[fa]+1;siz[u]=1;
for(int i=head[u];i;i=edge[i].next){
ll j=edge[i].to;
if(j==fa) continue;
dfs1(j,u);
siz[u]+=siz[j];
}
}
void dfs(ll u,ll fa,ll tw,ll fi){
fi+=siz[u]*five[u],tw+=siz[u]*two[u];
//cout<<fi<<" "<<tw<<" "<<u<<endl;
ans[u]=min(fi,tw);
for(int i=head[u];i;i=edge[i].next){
ll j=edge[i].to;
if(j==fa) continue;
dfs(j,u,tw-siz[j]*two[u],fi-siz[j]*five[u]);
}
}
int main(){
scanf("%lld%lld",&n,&q);
for(int i=1;i<n;i++){
ll u,v;
scanf("%lld%lld",&u,&v);
addedge(u,v);addedge(v,u);
}
for(ll i=1;i<=n;i++){
ll m=i;
while(m%2==0) two[i]++,m/=2;
while(m%5==0) five[i]++,m/=5;
//if(m){two[i]=0;five[i]=0;}
}
// cout<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"<<endl;
dfs1(1,0);
dfs(1,0,0,0);
while(q--){
ll x;
scanf("%lld",&x);
printf("%lld\n",ans[x]);
}
return 0;
}
[E-Longest Increasing Subsequence_"蔚来杯"2022牛客暑期多校训练营9 (nowcoder.com)](ac.nowcoder.com/acm/contest… "E-Longest Increasing Subsequence_"蔚来杯"2022牛客暑期多校训练营9 (nowcoder.com)")
看到m这么大先去想二进制,可以发现2,1,4,3,6,5这样的就符合二进制,6个数2个一组就是2的3次方,把数分解成二进制后反着存入数组中,相邻的1之前有x个0就在较前的1之前插入x个数,最后一个数一定是最大的
2022牛客暑期多校训练营9 个人题解 更新至5题 - 知乎 (zhihu.com)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1e6+100;
ll t,n,a[105];
int main(){
cin>>t;
while(t--){
scanf("%lld",&n);
vector<ll>v;
ll cnt=0,ma=0;
while(n){
a[cnt++]=n%2;
if(n%2) ma=cnt-1;
n/=2;
}
for(int i=1;i<=ma;i++) v.push_back(i*2),v.push_back(i*2-1);
ma*=2;
ll l=-1,len=0;
for(int i=0;i<cnt;i++){
if(a[i]==1){
if(l==-1) l=i;
else{
ll x=i-l;
for(int j=i-l;j;j--){
v.insert(v.begin()+len+l*2,ma+j);
}
len+=x;
ma+=x;
l=i;
}
}
}
v.push_back(++ma);
printf("%d\n",v.size());
for(int i=0;i<v.size();i++) printf("%lld ",v[i]);
printf("\n");
}
return 0;
}