多校冲刺 noip 11.13

多校冲刺 noip 11.13

我改题速度还是慢,慢死了

别人都改完了,我也改不完,我......

今天暴露很多问题,比如考场心态不稳,全靠第一题

比如数位\(DP\)根本不会,比如基环树学的像屎一样

T1 子集和

如果凑不够的话,只能加当前的数,不断地背包就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
const int N=55;
const int M=10005;
int n,m;
int a[N],cnt,b[M],v[M];
signed main(){
    freopen("subset.in","r",stdin);
    freopen("subset.out","w",stdout);
    n=read();m=read();
    fo(i,0,m)b[i]=read();
    v[0]=1;
    fo(i,0,m){
        int now=b[i]-v[i];
        if(!now)continue;
        while(now){
            a[++cnt]=i;
            fu(j,m,i)v[j]+=v[j-i];
            now=b[i]-v[i];
        }
    }
    fo(i,1,n)printf("%d ",a[i]);
    return 0;
}

T2 异或

一开始确实看错题了,以为一遍\(dfs\)就能解决

后来看出来之后,我一度想在\(trie\)树上放个线段树

转念一想发现可以直接用两颗\(trie\),枚举\(j\),动态更新答案就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
const int N=5e5+5;
int n,a[N];
ll ans,an[35][2];
struct TRIE{
    int son[N*32][2],siz[N*32];
    int seg=1;
}t[2];
void ins(int x,int id){
    int now=1;
    fu(i,30,0){
        int tmp=(x>>i)&1;
        if(!t[id].son[now][tmp])t[id].son[now][tmp]=++t[id].seg;
        an[i][0]-=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
        an[i][1]-=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
        t[id].siz[t[id].son[now][tmp]]++;
        an[i][0]+=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
        an[i][1]+=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
        now=t[id].son[now][tmp];
        //cout<<id<<" "<<x<<" "<<i<<" "<<now<<endl;
    }
}
void del(int x,int id){
    int now=1;
    fu(i,30,0){
        int tmp=(x>>i)&1;
        an[i][0]-=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
        an[i][1]-=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
        t[id].siz[t[id].son[now][tmp]]--;
        an[i][0]+=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
        an[i][1]+=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
        now=t[id].son[now][tmp];
    }
}
signed main(){
    freopen("xor.in","r",stdin);
    freopen("xor.out","w",stdout);
    // cerr<<(sizeof(t)+sizeof(a)+sizeof(an)>>20)<<endl;
    n=read();
    fo(i,1,n)a[i]=read(),ins(a[i],1);
    fo(i,1,n){
        del(a[i],1);
        fu(j,30,0)ans+=an[j][(a[i]>>j)&1];
        ins(a[i],0);
    }
    printf("%lld",ans);
    return 0;
}

T3 异或2

这个可以直接推式子??

也也可以数位\(DP\),这个主要思想是看有没有进位,然后退回去,计算方案数乘贡献就行了

这是摇摆\(B\)的思路

我直接推式子了,额,我不想写

需要高精度!!!!!

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int bas=1e16;
struct BIG{
    int x[155];
    BIG(){memset(x,0,sizeof(x));}
    void read(){
        char ch[1805];
        scanf("%s",ch+1);
        int len=strlen(ch+1);
        x[0]=(len-1)/16+1;
        fo(i,1,len){
            int now=len+1-i;
            int pos=(now-1)/16+1;
            x[pos]=(x[pos]<<3)+(x[pos]<<1)+ch[i]-'0';
        }
    }
    void write(){
        printf("%lld",x[x[0]]);
        fu(i,x[0]-1,1)printf("%016lld",x[i]);
        putchar('\n');
    }
    bool operator < (BIG a)const{
        if(x[0]!=a.x[0])return x[0]<a.x[0];
        fu(i,x[0],1)if(x[i]!=a.x[i])return x[i]<a.x[i];
        return false;
    }
    BIG operator * (int s)const{
        BIG ret;int jw;
        fo(i,1,x[0]){
            ret.x[i]+=x[i]*s;
            ret.x[i+1]+=ret.x[i]/bas;
            ret.x[i]=ret.x[i]%bas;
        }
        if(ret.x[x[0]+1])ret.x[0]=x[0]+1;
        else ret.x[0]=x[0];
        return ret;
    }
    BIG operator + (BIG a)const{
        BIG ret;
        fo(i,1,max(x[0],a.x[0])){
            ret.x[i]+=x[i]+a.x[i];
            ret.x[i+1]+=ret.x[i]/bas;
            ret.x[i]=ret.x[i]%bas;
        }
        if(ret.x[max(x[0],a.x[0])+1])ret.x[0]=max(x[0],a.x[0])+1;
        else ret.x[0]=max(x[0],a.x[0]);
        return ret;
    }
    BIG operator + (int s)const{
        BIG ret=*this;
        ret.x[1]+=s;
        fo(i,1,x[0]){
            ret.x[i+1]+=ret.x[i]/bas;
            ret.x[i]=ret.x[i]%bas;
        }
        if(ret.x[x[0]+1])ret.x[0]=x[0]+1;
        else ret.x[0]=x[0];
        return ret;
    }
    BIG operator - (BIG a)const{
        BIG ret;
        fo(i,1,x[0]){
            ret.x[i]+=x[i]-a.x[i];
            if(ret.x[i]<0)ret.x[i]+=bas,ret.x[i+1]-=1;
        }
        ret.x[0]=x[0];
        while(!ret.x[ret.x[0]]&&ret.x[0]>1)ret.x[0]--;
        return ret;
    }
    BIG operator - (int s)const{
        BIG ret=*this;
        ret.x[1]-=s;
        fo(i,1,x[0]){
            if(ret.x[i]>=0)break;
            ret.x[i+1]--;
            ret.x[i]+=bas;
        }
        if(!ret.x[x[0]]&&x[0]>1)ret.x[0]=x[0]-1;
        else ret.x[0]=x[0];
        return ret;
    }
    BIG operator / (int s)const{
        BIG ret=*this;
        fu(i,x[0],2){
            if(ret.x[i]&1)ret.x[i-1]+=bas;
            ret.x[i]>>=1;
        }
        ret.x[1]>>=1;
        if(!ret.x[x[0]])ret.x[0]=x[0]-1;
        else ret.x[0]=x[0];
        return ret;
    }
}n,ans;
map<BIG,BIG> mp;
BIG dfs(BIG x){
    
    if(mp.find(x)!=mp.end())return mp[x];
    if(x.x[0]==1&&x.x[1]==1){
        mp[x].x[0]=1;mp[x].x[1]=2;
        return mp[x];
    }
    if(x.x[0]==1&&x.x[1]==0){
        mp[x].x[0]=1;mp[x].x[0]=0;
        return mp[x];
    }
    if(x.x[1]&1)return mp[x]=dfs(x/2)*4+x+1;
    else return mp[x]=dfs(x/2)*2+dfs(x/2-1)*2;
}
signed main(){
    freopen("rox.in","r",stdin);
    freopen("rox.out","w",stdout);
    n.read();
    ans=dfs(n)-n*2;
    ans.write();
    return 0;
}

T4 卡牌游戏

发现如果从正面向反面连边,那么每个点至多有一条出边

所以我们对边进行反转,相当于对卡牌进行翻转

直接统计答案就好了

对我的基环树\(DP\)有了很大的提升

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
    int s=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
const int N=2e5+5;
const int mod=998244353;
int n,ans1,ans2=1;
int to[N*2],nxt[N*2],val[N*2],head[N*2],rp=1;
void add_edg(int x,int y,int z){
    to[++rp]=y;
    val[rp]=z;
    nxt[rp]=head[x];
    head[x]=rp;
}
bool vis[N],cat[N];
int dp[N];
int dfs_rt(int x,int f){
    int ret=0;
    for(int i=head[x];i;i=nxt[i]){
        if(cat[i])continue;
        int y=to[i];
        if(y==f)continue;
        ret+=dfs_rt(y,x);
        ret+=val[i];
    }
    return ret;
}
int mn,sum;
void dfs_oth(int x,int f){
    if(mn>dp[x])mn=dp[x],sum=1;
    else if(mn==dp[x])sum++;
    for(int i=head[x];i;i=nxt[i]){
        if(cat[i])continue;
        int y=to[i];
        if(y==f)continue;
        if(val[i])dp[y]=dp[x]-1;
        else dp[y]=dp[x]+1;
        dfs_oth(y,x);
    }
}
int s,t,b;
bool flag=true;
void dfs_cir(int x,int f){
    vis[x]=true;
    for(int i=head[x];i;i=nxt[i]){
        if(cat[i])continue;
        int y=to[i];
        if(y==f)continue;
        if(vis[y]){
            cat[i]=cat[i^1]=true;
            if(s)flag=false;
            s=x;t=y;b=i;
            continue;
        }
        dfs_cir(y,x);
    }
}
signed main(){
    freopen("card.in","r",stdin);
    freopen("card.out","w",stdout);
    n=read();
    fo(i,1,n){
        int x=read(),y=read();
        add_edg(x,y,1);
        add_edg(y,x,0);
    }
    fo(i,1,2*n){
        if(vis[i]||!head[i])continue;
        s=t=0;dfs_cir(i,0);
        if(!s){
            dp[i]=dfs_rt(i,0);
            mn=0x3f3f3f3f3f3f3f3f;sum=1;
            dfs_oth(i,0);
            ans1+=mn;ans2=ans2*sum%mod;
            //cerr<<mn<<endl;
        }
        else {
            //cerr<<"fuck"<<endl;
            dp[i]=dfs_rt(i,0);
            dfs_oth(i,0);
            if(s!=t){
                if(b&1)dp[to[b^1]]++;
                else dp[to[b]]++;
            }
            if(dp[s]==dp[t]&&s!=t)ans1+=dp[s],ans2=ans2*2%mod;
            else ans1+=min(dp[s],dp[t]);
        }
    }
    cerr<<ans1<<" "<<ans2<<endl;
    if(!flag)ans1=ans2=-1;
    printf("%lld %lld",ans1,ans2);
}
posted @ 2021-11-13 20:36  fengwu2005  阅读(45)  评论(0编辑  收藏  举报