2021.11.13考试总结[冲刺NOIP模拟29]

T1 子集和

最小的元素可以直接确定下来。接下来不断做背包删去这个元素,递归进行即可。

\(code:\)

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

namespace IO{
    #define int long long
    char Ch[50];
    int read(){
        int x=0,f=1; char Ch=getchar();
        while(Ch<'0'||Ch>'9'){ if(Ch=='-') f=-1; Ch=getchar(); }
        while(Ch>='0'&&Ch<='9'){ x=(x<<1)+(x<<3)+(Ch^48); Ch=getchar(); }
        return x*f;
    }  
    void write(int x,int sp){
        int len=0;
        if(x<0){ putchar('-'); x=-x; }
        do{ Ch[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(Ch[i]); putchar(sp);
    }
} using namespace IO;

const int NN=10010;
int n,m,b[NN],a[60],f[500010];

signed main(){
    freopen("subset.in","r",stdin);
    freopen("subset.out","w",stdout);
    n=read(); m=read();
    for(int i=0;i<=m;i++) b[i]=read();
    b[0]=0;
    while(!b[a[1]]) ++a[1];
    f[0]=f[a[1]]=1; --b[a[1]];
    for(int i=2;i<=n;i++){
        a[i]=a[i-1];
        while(!b[a[i]]) ++a[i];
        for(int j=m;j>=a[i];j--){
            b[j]-=f[j-a[i]];
            f[j]+=f[j-a[i]];
        }
    }
    for(int i=1;i<=n;i++) write(a[i],' ');
    return puts(""),0;
}

T2 异或

好像能trie树做?

可以枚举每一位,在这一位 \(bit\) 上产生贡献的 \(i\)\(k\) 满足 \(a_i,a_k\)\(bit\) 位之前相同,且在第 \(bit\) 位不同。中间的 \(j\)\(bit\) 位与 \(a_i\) 相同就行。

因此对每一位扫一遍,记下到 \(i\) 为止 \(bit\) 位之前部分为 \(rest\) ,且第 \(bit\) 位为 \(now\) 的数量为 \(num_{i,rest,now}\) ,单纯第 \(bit\) 位为 \(now\) 的数量为 \(sum_{i,now}\)

那么对位置 \(k\) ,令它之前与它的 \(rest\) 相同的位置为 \(pos\) ,那么它与他之前的数的贡献即为

\[\sum_{pos} (sum_{k,now\bigoplus1}-sum_{pos,now\bigoplus1})=sum_{k,now\bigoplus1}\times num_{k,rest,now\bigoplus1}-\sum_{pos}sum_{pos,now\bigoplus1} \]

\(rest\) 意义下 \(\sum_{pos}sum_{pos,now}\)\(pre_{rest,now}\) ,在线更新即可做到复杂度 \(O(30n)\)

\(code:\)

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

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

const int NN=500010;
int n,tot,a[NN],num[2][NN];
LL ans,sum[2],pre[2][NN];
unordered_map<int,int>has;

void clear(){
    has.clear();
    tot=sum[0]=sum[1]=0;
    memset(num,0,sizeof(num));
    memset(pre,0,sizeof(pre));
}
signed main(){
    freopen("xor.in","r",stdin);
    freopen("xor.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=30;i;i--){
        clear();
        for(int j=1;j<=n;j++){
            int now=(a[j]>>i-1)&1,rest=a[j]>>i;
            if(!has[rest]) has[rest]=++tot;
            rest=has[rest];
            ans+=sum[now^1]*num[now^1][rest]+pre[now^1][rest];
            ++num[now][rest]; ++sum[now];
            pre[now][rest]-=sum[now];
        }
    }
    write(ans,'\n');
    return 0;
}

T3 异或2

推式子加高精的离谱题。
image

记忆化搜索。 map可以用哈希映射。(好像也可以不用

\(code:\)

T3
#include<bits/stdc++.h>
#define int long long
using namespace std;

namespace IO{
    char Ch[50];
    int read(){
        int x=0,f=1; char Ch=getchar();
        while(Ch<'0'||Ch>'9'){ if(Ch=='-') f=-1; Ch=getchar(); }
        while(Ch>='0'&&Ch<='9'){ x=(x<<1)+(x<<3)+(Ch^48); Ch=getchar(); }
        return x*f;
    }  
    void write(int x,int sp){
        int len=0;
        if(x<0){ putchar('-'); x=-x; }
        do{ Ch[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(Ch[i]); putchar(sp);
    }
} using namespace IO;

namespace Big_Integers{
    const int base=1e16;
    typedef __uint128_t ULL;
    struct big{
        int l,c[100];
        ULL has;
        big(){}
        big(int x){ memset(c,0,sizeof(c)); l=1; c[1]=x; }
        void calc(){ has=l; for(int i=1;i<=l;i++) has*=c[i]; }
        void print(){ printf("%lld",c[l]);for(int i=l-1;i>0;i--)printf("%016lld",c[i]);puts(""); }
        big operator+(const big& a)const{
            big res=big(0); res.l=max(l,a.l);
            for(int i=1;i<=res.l;i++){
                res.c[i]+=c[i]+a.c[i];
                res.c[i+1]+=res.c[i]/base;
                res.c[i]%=base;
            }
            if(res.c[res.l+1]) ++res.l;
            res.calc();
            return res;
        }
        big operator-(const int& a)const{
            big res=big(0); res.l=l;
            for(int i=1;i<=l;i++) res.c[i]=c[i];
            int pos=1; res.c[1]-=a;
            while(res.c[pos]<0){
                res.c[pos]+=base;
                ++pos; --res.c[pos];
            }
            if(!res.c[res.l]) --res.l;
            res.calc();
            return res;
        }
        big operator*(const int& a)const{
            big res=big(0); res.l=l;
            for(int i=1;i<=l;i++){
                res.c[i]+=c[i]*a;
                res.c[i+1]+=res.c[i]/base;
                res.c[i]%=base;
            }
            if(res.c[res.l+1]) ++res.l;
            res.calc();
            return res;
        }
        big operator/(const int& a)const{
            big res=big(0); res.l=l;
            for(int i=1;i<=l;i++) res.c[i]=c[i];
            if(res.c[1]&1) --res.c[1];
            for(int i=l;i;i--){
                if(res.c[i]&1) res.c[i-1]+=base;
                res.c[i]/=a;
            }
            if(!res.c[l]) --res.l;
            res.calc();
            return res;
        }
    }n;
    big Read(){
        big res=big(0);
        char ch[1000]; scanf("%s",ch+1);
        int len=strlen(ch+1);
        for(int i=1;i<=len;i++)
            res=res*10+big(ch[i]-'0');
        return res;
    }
    map<ULL,big>f;
} using namespace Big_Integers;

big dfs(big now){
    if(now.l<=1&&now.c[1]<=0) return f[now.has]=big(0);
    if(f.find(now.has)!=f.end()) return f[now.has];
    big k=now/2;
    if(now.c[1]&1) f[now.has]=dfs(k)*4+k*6;
    else f[now.has]=dfs(k)*2+dfs(k-1)*2+k*4-4;
    return f[now.has];
}

signed main(){
    freopen("rox.in","r",stdin);
    freopen("rox.out","w",stdout);
    n=Read();
    dfs(n).print();
    return 0;
}

T4 卡牌游戏

是没切的原题。。

把每张卡牌看做一条有向边,由 \(a_i\) 指向 \(b_i\) ,那么操作实际上就是把边翻转,使最后每个点的出度都小于等于 \(1\) 。因此可以得出,有解当且仅当每个联通块都是一棵树或基环树。

为了方便,把单向边看作双向边,点权为 \(1\) 代表边从起点指向终点,反之为 \(0\)

不难发现,最后状态一定为若干棵(基环)内向树。

于是对每个联通块分别计算。对于树,可以直接换根DP,根由 \(u\) 变为 \(v\) 时需要改变的边只有 \(u\to v\) ,按边权讨论即可。对于基环树,可以讨论环的方向。集体来说,可以先删去环上的一条边按树处理,之后讨论删去的边的方向就行了。

\(code:\)

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

namespace IO{
    #define int long long
    #define mpr make_pair
    #define fi first
    #define se second
    typedef pair<int,int>PII;
    char Ch[50];
    int read(){
        int x=0,f=1; char Ch=getchar();
        while(Ch<'0'||Ch>'9'){ if(Ch=='-') f=-1; Ch=getchar(); }
        while(Ch>='0'&&Ch<='9'){ x=(x<<1)+(x<<3)+(Ch^48); Ch=getchar(); }
        return x*f;
    }  
    void write(int x,int sp){
        int len=0;
        if(x<0){ putchar('-'); x=-x; }
        do{ Ch[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(Ch[i]); putchar(sp);
    }
} using namespace IO;

const int NN=200010,mod=998244353;
int n,m,ansf,anss;

namespace Graph{
    int idx,head[NN];
    int en,pn,fr,to,pos,cnt;
    int f[NN],g[NN];
    bool vis[NN];
    vector<int>vec;
    struct edge{
        int to,nex;
        bool w;
    }e[NN<<1];
    void add(int a,int b){
        e[++idx]=(edge){b,head[a],1}; head[a]=idx;
        e[++idx]=(edge){a,head[b],0}; head[b]=idx;
    }
    void check_dfs(int s){
        ++pn; vis[s]=1;
        for(int v,i=head[s];i;i=e[i].nex){
            v=e[i].to; ++en;
            if(!vis[v]) check_dfs(v);
        }
    }
    void check(){
        for(int i=1;i<=m;i++) if(!vis[i]){
            en=pn=0; check_dfs(i);
            if(en>pn*2) puts("-1 -1"),exit(0);
        }
        memset(vis,0,sizeof(vis));
    }
    void pre_dfs(int s,int fa){
        vis[s]=1;
        for(int v,i=head[s];i;i=e[i].nex) if((v=e[i].to)!=fa){
            if(vis[v]){
                fr=s; to=v; pos=i;
                continue;
            }
            pre_dfs(v,s);
            f[s]+=f[v]+e[i].w;
        }
    }
    void work_dfs(int s,int fa){
        vec.push_back(g[s]);
        for(int v,i=head[s];i;i=e[i].nex) if((v=e[i].to)!=fa){
            if(i==pos||i==(pos^1)) continue;
            g[v]=g[s]+(e[i].w?-1:1);
            work_dfs(v,s);
        }
    }
} using namespace Graph;

signed main(){
    freopen("card.in","r",stdin);
    freopen("card.out","w",stdout);
    n=read(); m=n<<1; idx=1; anss=1;
    for(int a,b,i=1;i<=n;i++)
        a=read(),b=read(),add(a,b);
    check();
    for(int i=1;i<=m;i++) if(!vis[i]){
        fr=to=pos=cnt=0; vec.clear();
        pre_dfs(i,0); g[i]=f[i]; work_dfs(i,0);
        if(!pos){
            sort(vec.begin(),vec.end());
            for(int v:vec)
                if(v==vec[0]) ++cnt;
                else break;
            ansf+=vec[0]; (anss*=cnt)%=mod;
        } else if(fr==to) ansf+=min(g[fr],g[to]);
        else{
            if(!e[pos].w) pos^=1;
            (e[pos].to==to)?++g[to]:++g[fr];
            cnt=1+(g[to]==g[fr]);
            ansf+=min(g[to],g[fr]); (anss*=cnt)%=mod;
        }
    }
    write(ansf,' '); write(anss,'\n');
    return 0;
}
posted @ 2021-11-13 18:28  keen_z  阅读(39)  评论(0)    收藏  举报