1. 程式人生 > >清北考前刷題day3下午好

清北考前刷題day3下午好

sum namespace 有環 方案 .net 數位 pre 一個 路徑

技術分享

技術分享

/*
可以並查集維護
可以發現,某個聯通快出現大於等於2個環,一定無法分配。
有解要麽一個環,要麽沒有環。
一個環時答案等於點數乘2(順時針或逆時針)。
沒有環是樹,對於一個n個點的樹,方案一定有n種(不連某個點)。
*/
#include<iostream>
#include<cstdio>
#include<cstring>

#define N 100007
#define mod 1000000007
#define ll long long

using namespace std;
ll n,m,ans,cnt;
ll fa[N],siz[N],num[N];
bool vis[N]; inline ll read() { ll x=0,f=1;char c=getchar(); while(c>9||c<0){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} return x*f; } ll find(ll x){return x==fa[x]?x:fa[x]=find(fa[x]);} void merge(ll x,ll y) { fa[y]
=x; siz[x]+=siz[y];num[x]+=num[y]; } int main() { ll x,y;ans=1; n=read();m=read(); for(ll i=1;i<=n;i++) fa[i]=i,siz[i]=1; for(ll i=1;i<=m;i++) { x=read();y=read(); ll r1=find(x),r2=find(y); if(r1!=r2) merge(r1,r2); else num[r1]++; }
for(ll i=1;i<=n;i++) { ll now=find(i); if(vis[now]) continue;vis[now]=1; if(num[now]>2) continue; if(num[now]==1) ans=(ans*2)%mod; if(!num[now]) ans=(ans*siz[now])%mod; } printf("%lld\n",ans%mod); return 0; }

技術分享

/*
若兩數k進制下相同
那麽k進制後它們一定偶數位為0,奇數位為0~k-1
從高位遞推可能的情況累加答案即可。 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>

#define N 100
#define ll long long

using namespace std;
ll n,k,ans,cnt,len;
ll Pow[N];
int a[N];

int main()
{
    scanf("%lld%lld",&n,&k);
    while(n){Pow[++len]=n%k;n/=k;}
    if(len%2==0)
    {
        ans=pow(k,len>>1);
        printf("%lld\n",ans);
    }
    else
    {
        for(int i=len;i>=1;i--)
        {
            if(Pow[i])
            {
                if(i%2==0)
                {
                    ans+=1ll*pow(k,i/2);
                    break;
                }
                else ans+=1ll*Pow[i]*pow(k,i/2);
                if(i==1) ++ans;
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

旅行

技術分享

技術分享

/*
嗯,需要維護每個點到根的距離。
首先開始的時候選取葉子結點一定比中間節點優。 
當選擇了一條鏈的時候,會對哪些點有影響呢?
答案當然是在這條鏈上的點的子樹。把這個點的子樹權值減掉這個點的權值就好。
看到子樹,想到dfs序。又因為要查詢最大值,所以可以想到用線段樹實現。
線段樹每個節點維護原樹每個點到根的距離的最大值和原樹每個節點dfs序所對應的點的編號。 
每次查詢區間最大值,然後刪去這條鏈,每次刪的時候更新子樹權值(區間減法)。
刪除把這個點的權值賦值為0就好。然後往上走,走的時候到某個點權值為0那麽就停。
因為如果某個點權值為0,那麽他到根的路徑上所有點權都為零。恩。 
*/
#include<iostream>
#include<cstdio>
#include<cstring>

#define N 200007
#define ll long long

using namespace std;
ll n,m,ans,cnt,tot;
ll head[N],dis[N],fa[N];
ll S[N],pos[N],T[N],a[N];
struct edge{
    int u,v,net,w;
}e[N<<1];
struct tree{
    ll l,r,mx,pos,flag;
}tr[N<<2];

namespace seg
{
    void pushup(int k)
    {
        if(tr[k<<1].mx>tr[k<<1|1].mx) tr[k].mx=tr[k<<1].mx,tr[k].pos=tr[k<<1].pos;
        else tr[k].mx=tr[k<<1|1].mx,tr[k].pos=tr[k<<1|1].pos;
    }
    void pushdown(int k)
    {
        tr[k<<1].flag+=tr[k].flag;tr[k<<1|1].flag+=tr[k].flag;
        tr[k<<1].mx+=tr[k].flag;tr[k<<1|1].mx+=tr[k].flag;
        tr[k].flag=0;
    }
    void build(int k,int l,int r)
    {
        tr[k].l=l;tr[k].r=r;
        if(l==r) 
        {
            tr[k].mx=dis[pos[l]],tr[k].pos=pos[l];
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid);build(k<<1|1,mid+1,r);
        pushup(k);
    }
    void update(int k,int l,int r,int z)
    {
        if(tr[k].l==l && tr[k].r==r) 
        {
            tr[k].mx+=z;tr[k].flag+=z;
            return;
        }
        pushdown(k);
        int mid=tr[k].l+tr[k].r>>1;
        if(r<=mid) update(k<<1,l,r,z);
        else if(l>mid) update(k<<1|1,l,r,z);
        else update(k<<1,l,mid,z),update(k<<1|1,mid+1,r,z);
        pushup(k);
    }

}using namespace seg;

inline void add(int u,int v)
{
    e[++cnt].v=v;e[cnt].net=head[u];head[u]=cnt;
}

inline ll read()
{
    ll x=0,f=1;char c=getchar();
    while(c>9||c<0){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}

void dfs(int u,int last,ll sum)
{
    S[u]=++tot;pos[tot]=u;dis[u]=sum;
    for(int i=head[u];i;i=e[i].net)
    {
        int v=e[i].v;
        if(v==last) continue;
        fa[v]=u;dfs(v,u,sum+a[v]);
    }T[u]=tot;
}

void change(int u)
{
    while(a[u])
    {
        update(1,S[u],T[u],-a[u]);
        a[u]=0;u=fa[u];
    }
}

int main()
{
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    int x,y;
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<n;i++) 
    {
        x=read();y=read();
        add(x,y);add(y,x);
    }ans=a[1];a[1]=0;dfs(1,0,0);
    build(1,1,n);
    while(m--)
    {
        tree Tr=tr[1];ans+=Tr.mx;
        change(Tr.pos);
    }
    printf("%lld\n",ans);
    return 0;
}

清北考前刷題day3下午好