2021.9.13考试总结[NOIP模拟52]

T1 路径


考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int unsigned long long
 3 using namespace std;
 4 
 5 namespace IO{
 6     inline int read(){
 7         char ch=getchar(); int x=0,f=1;
 8         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 9         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
10         return x*f;
11     }
12     inline void write(int x,char sp){
13         char ch[50]; int len=0;
14         if(x<0){ putchar('-'); x=~x+1; }
15         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
16         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17     }
18     inline int max(int x,int y){ return x<y?y:x; }
19     inline int min(int x,int y){ return x<y?x:y; }
20     inline void swap(int &x,int &y){ x^=y^=x^=y; }
21     inline void chmax(int &x,int y){ x=x<y?y:x; }
22     inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24 
25 const int NN=70;
26 int x,n,ext,ans;
27 
28 signed main(){
29     x=n=read();
30     while(n){ ++ext; n>>=1; }
31     for(int i=0;i<ext;i++) ans+=x/(1ll<<i);
32     write(ans,'\n');
33     return 0;
34 }
T1

考场思路:

考虑式子实际意义,其实为每个数末尾连续$1$的个数加一的和。

于是可以数位$DP$。

但我没有。考虑上界$n-1$,扫描每一二进制位,将每个$1$变成$0$,都会给答案带来贡献。

具体来说,由低数第$i$为是$1$,会给末尾有$j$个连续$1$的数的个数带来$2^(i-j)$的贡献。最后容斥,统计答案。

注意如果扫到的$1$到末尾一直是$1$,则会给当前位带来额外$1$的贡献。以及

左移要写$1LL$!!

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 
 5 namespace IO{
 6     inline int read(){
 7         char ch=getchar(); int x=0,f=1;
 8         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 9         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
10         return x*f;
11     }
12     inline void write(int x,char sp){
13         char ch[20]; int len=0;
14         if(x<0){ putchar('-'); x=~x+1; }
15         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
16         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17     }
18     inline int max(int x,int y){ return x<y?y:x; }
19     inline int min(int x,int y){ return x<y?x:y; }
20     inline void swap(int &x,int &y){ x^=y^=x^=y; }
21     inline void chmax(int &x,int y){ x=x<y?y:x; }
22     inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24 
25 const int NN=70;
26 int x,n,ans,ext,sum,lmt[NN],num[NN];
27 bool link;
28 
29 signed main(){
30     x=ans=n=read(); --n; --x; link=1;
31     while(x){
32         lmt[++ext]=x&1;
33         x>>=1;
34     }
35     for(int i=1;i<=ext;i++){
36         if(!lmt[i]){ link=0; continue;}
37         if(lmt[i]) for(int j=1;j<i;j++) num[j]+=1ll<<(i-j-1);
38         if(link) ++num[i];
39     }
40     for(int i=ext;i;i--){
41         num[i]-=sum;
42         sum+=num[i];
43         ans+=i*num[i];
44     }
45     write(ans,'\n');
46     return 0;
47 }
T1考场

T2 赌神


大力推式子(但我不会

玄学做法:

考虑自己的最优方案,一定是要尽力令颜色数减少,但同时自己不能亏损,所以每次应按比例下注。

幕后黑手要尽力使颜色数不减少,所以每次投出颜色最多的球。

模拟即可。

其实由于自己每次取最优策略,不管幕后黑手怎样处理结果都不会改变。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 
 5 namespace IO{
 6     inline int read(){
 7         char ch=getchar(); int x=0,f=1;
 8         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 9         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
10         return x*f;
11     }
12     inline void write(int x,char sp){
13         char ch[20]; int len=0;
14         if(x<0){ putchar('-'); x=~x+1; }
15         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
16         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17     }
18     inline int max(int x,int y){ return x<y?y:x; }
19     inline int min(int x,int y){ return x<y?x:y; }
20     inline void swap(int &x,int &y){ x^=y^=x^=y; }
21     inline void chmax(int &x,int y){ x=x<y?y:x; }
22     inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24 
25 const int NN=1e6+5,p=998244353;
26 int n,ans,sum,num;
27 priority_queue<int>q;
28 
29 inline int inv(int x){
30     int res=1,b=p-2;
31     while(b){
32         if(b&1) res=res*x%p;
33         x=x*x%p;
34         b>>=1;
35     }
36     return res;
37 }
38 
39 signed main(){
40     n=read(); ans=1;
41     for(int i=1;i<=n;i++){ 
42         num=read();
43         sum+=num;
44         q.push(num);
45     }
46     while(sum){
47         int x=q.top(); q.pop(); 
48         if(x-1) q.push(x-1);
49         ans=ans*n%p*x%p*inv(sum)%p;
50         --sum;
51     }
52     write(ans,'\n');
53     return 0;
54 }
T2

T3 路径


数据太弱,$O(n^2log)$点分治都能A。。

点分治带个$fft$或$ntt$可以到$O(nlog^2)$,可A。但不会。

正解斯特林数+换根$DP$。

$x^k=\sum_{i=1}^k \begin{Bmatrix}k\\ i\end{Bmatrix}\times x^{\underline i}$

 有$(x+1)^{\underline i}=i\times x^{\underline{i-1}}+x^{\underline i}$。

设$f_{i,j}$为$i$子树中所有点到$i$距离的$j$次下降幂之和,$g_{i,j}$为$i$子树中所有点到$i$父亲距离的$j$次下降幂之和。那么有

$f_{i,j}=\sum_{u\in son_i}g_{u,j}$,$g_{i,j}=j\times f_{i,j-1}+f_{i,j}$。

换根时考虑原来根的$f$,减去新根的$g$;新根的$f$加上由原来根的$f$通过上面式子算出的$g$。

$code:$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 namespace IO{
 5     inline int read(){
 6         char ch=getchar(); int x=0,f=1;
 7         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 8         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 9         return x*f;
10     }
11     inline void write(int x,char sp){
12         char ch[20]; int len=0;
13         if(x<0){ putchar('-'); x=~x+1; }
14         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
15         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
16     }
17     inline int max(int x,int y){ return x<y?y:x; }
18     inline int min(int x,int y){ return x<y?x:y; }
19     inline void swap(int &x,int &y){ x^=y^=x^=y; }
20     inline void chmax(int &x,int y){ x=x<y?y:x; }
21     inline void chmin(int &x,int y){ x=x<y?x:y; }
22 } using namespace IO;
23 
24 const int NN=1e6+5,p=998244353,inv2=499122177;
25 int n,k,ans,f[NN][105],g[NN][105],sum[105];
26 int idx,to[NN<<1],nex[NN<<1],head[NN],s[105][105];
27 
28 inline void add(int a,int b){
29     to[++idx]=b; nex[idx]=head[a]; head[a]=idx;
30     to[++idx]=a; nex[idx]=head[b]; head[b]=idx;
31 }
32 
33 void init(){
34     s[1][1]=1;
35     for(int i=2;i<=k;i++) for(int j=1;j<=i;j++)
36         s[i][j]=(s[i-1][j-1]+1ll*j*s[i-1][j]%p)%p;
37 }
38 
39 void dfs(int st,int fa){
40     int ext=0;
41     for(int i=head[st];i;i=nex[i]){
42         int v=to[i];
43         if(v==fa) continue;
44         dfs(v,st);
45         for(int i=0;i<=k;i++){
46             if(!g[v][i]) break;
47             chmax(ext,i);
48             (f[st][i]+=g[v][i])%=p;
49         }
50     }
51     ++f[st][0]; ext=min(k,ext+1);
52     for(int i=ext;i;i--)
53         g[st][i]=(1ll*i*f[st][i-1]%p+f[st][i])%p;
54     g[st][0]=f[st][0];
55 }
56 
57 void getans(int st,int fa){
58     int ext=0,tmp[105];
59     for(int i=0;i<=k;i++){
60         if(!f[st][i]) break;
61         chmax(ext,i);
62         (sum[i]+=f[st][i])%=p;
63     }
64     ext=min(k,ext+1);
65     for(int i=head[st];i;i=nex[i]){
66         int v=to[i];
67         if(v==fa) continue;
68         for(int j=0;j<=ext;j++) tmp[j]=(f[st][j]-g[v][j]+p)%p;
69         for(int j=ext;j;j--) tmp[j]=(1ll*tmp[j-1]*j%p+tmp[j])%p;
70         for(int j=0;j<=ext;j++) (f[v][j]+=tmp[j])%=p;
71         getans(v,st);
72     }
73 }
74 
75 signed main(){
76     n=read(); k=read(); init();
77     for(int a,b,i=1;i<n;i++)
78         a=read(),b=read(), add(a,b);
79     dfs(1,0); getans(1,0);
80     for(int i=0;i<=k;i++) (ans+=1ll*s[k][i]*sum[i]%p)%=p;
81     ans=1ll*ans*inv2%p;
82     write(ans,'\n');
83     return 0;
84 }
T3

UPD:联赛后做到了原题。重构了一遍代码,更可读了。

exT3
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    typedef long long LL;
    typedef double DB;
    int read(){
        int x=0,f=0; char ch=getchar();
        while(ch>'9'||ch<'0'){ f|=(ch=='-'); ch=getchar(); }
        while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return f?-x:x;
    } char output[50];
    void write(int x,char sp){
        int len=0;
        if(x<0) putchar('-'), x=-x;
        do{ output[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
    }
    void ckmax(int& x,int y){ x=x>y?x:y; }
    void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=50010,KK=510,mod=10007;
int n,k,t,ans[NN],tmp[KK],s[KK][KK],f[NN][KK],g[NN][KK];
vector<int>e[NN];

void dfs(int u,int p){
    for(int v:e[u]) if(v!=p){
        dfs(v,u);
        for(int i=0;i<=k;i++)
            f[u][i]=(f[u][i]+g[v][i])%mod;
    }
    g[u][0]=++f[u][0];
    for(int i=1;i<=k;i++)
        g[u][i]=(i*f[u][i-1]+f[u][i])%mod;
}
void redfs(int u,int p){
    for(int i=1;i<=k;i++)
        ans[u]=(ans[u]+s[k][i]*f[u][i])%mod;
    for(int v:e[u]) if(v!=p){
        for(int i=0;i<=k;i++) tmp[i]=(mod+f[u][i]-g[v][i])%mod;
        for(int i=k;i>=1;i--) tmp[i]=(tmp[i]+tmp[i-1]*i%mod)%mod;
        for(int i=0;i<=k;i++) f[v][i]=(f[v][i]+tmp[i])%mod;
        redfs(v,u);
    }
}

signed main(){
    s[0][0]=1;
    for(int i=1;i<=500;i++)
        for(int j=1;j<=500;j++)
            s[i][j]=(s[i-1][j]*j+s[i-1][j-1])%mod;
    t=read();
    while(t--){
        n=read(); k=read();
        for(int u,v,i=1;i<n;i++){
            u=read(); v=read();
            e[u].push_back(v);
            e[v].push_back(u);
        }
        dfs(1,0); redfs(1,0);
        for(int i=1;i<=n;i++) write(ans[i],'\n');
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++) e[i].clear();
    }
    return 0;
}

T4 树


暴力分层动态开点线段树:

$code:$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 namespace IO{
 5     inline int read(){
 6         char ch=getchar(); int x=0,f=1;
 7         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 8         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 9         return x*f;
10     }
11     inline void write(int x,char sp){
12         char ch[20]; int len=0;
13         if(x<0){ putchar('-'); x=~x+1; }
14         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
15         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
16     }
17     inline int max(int x,int y){ return x<y?y:x; }
18     inline int min(int x,int y){ return x<y?x:y; }
19     inline void swap(int &x,int &y){ x^=y^=x^=y; }
20     inline void chmax(int &x,int y){ x=x<y?y:x; }
21     inline void chmin(int &x,int y){ x=x<y?x:y; }
22 } using namespace IO;
23 
24 const int NN=3e5+5;
25 int n,q,x,y,z,v,mx,op,cnt,idx,siz[NN],dfn[NN],to[NN<<1],nex[NN<<1],head[NN],w[NN],dep[NN];
26 
27 inline void add(int a,int b){
28     to[++idx]=b; nex[idx]=head[a]; head[a]=idx;
29     to[++idx]=a; nex[idx]=head[b]; head[b]=idx;
30 }
31 
32 void dfs(int s,int f){
33     dfn[s]=++cnt; dep[s]=dep[f]+1; siz[s]=1;
34     chmax(mx,dep[s]);
35     for(int i=head[s];i;i=nex[i])
36         if(to[i]!=f) dfs(to[i],s), siz[s]+=siz[to[i]];
37 }
38 
39 namespace segment_tree{
40     int tot,root[NN],lc[NN*80],rc[NN*80],val[NN*80];
41     void insert(int &rt,int l,int r,int opl,int opr,int vv){
42         if(!rt) rt=++tot;
43         if(l>=opl&&r<=opr) return val[rt]+=vv,void();
44         int mid=l+r>>1;
45         if(opl<=mid) insert(lc[rt],l,mid,opl,opr,vv);
46         if(opr>mid) insert(rc[rt],mid+1,r,opl,opr,vv);
47     }
48     int query(int rt,int l,int r,int pos,int ans){
49         ans+=val[rt];
50         if(l==r) return ans;
51         int mid=l+r>>1;
52         if(pos<=mid) return query(lc[rt],l,mid,pos,ans);
53         else return query(rc[rt],mid+1,r,pos,ans);
54     }
55 } using namespace segment_tree;
56 
57 signed main(){
58     n=read(); q=read();
59     for(int a,b,i=1;i<n;i++)
60         a=read(),b=read(), add(a,b);
61     dfs(1,0);
62     while(q--){
63         op=read();
64         if(op==1){
65             v=read(); x=read(); y=read(); z=read();
66             int tmp=y+dep[v];
67             while(tmp<=mx){
68                 insert(root[tmp],1,n,dfn[v],dfn[v]+siz[v]-1,z);
69                 tmp+=x;
70             }
71         }
72         else{ 
73             v=read();
74             write(query(root[dep[v]],1,n,dfn[v],0),'\n');
75         }
76     }
77     return 0;
78 }
T4暴力

正解离线分块,待补(不补

posted @ 2021-09-13 19:37  keen_z  阅读(38)  评论(0编辑  收藏  举报