雅禮學習10.4

來源:互聯網
上載者:User

標籤:節點   這不   產生樹   分享圖片   main   temp   其他   bool   解決   

雅禮學習10.4上午考試各題狀況T1

莫名其妙20分了。

考場上一眼秒掉了這個題目:這不就是個並查集捆綁+快速冪麼

然後開開心心這個點如果有這個質因子的話\(fa\)就指向這個質因子,而每個數字有多個質因子。。。

多個質因子在相互指\(fa\)的時候指亂套了。。。。

對拍的時候看出來的,然後用\(1\)個多小時來調這份代碼,最後自己都不知道這東西在幹嘛了,就涼了。

T2

寫了個暴力枚舉,期望\(20\)實際\(20\)

T3

看到成績之後:這題怎麼會爆\(long long\)的???

然後講題的時候。。。出題人說第二個部分分裡面\(a_i\)的取值範圍給錯了,少了三個零。。。

涼涼,\(30\)掛沒了

題目及考場代碼T1

#include <cstdio>#include <cstring>inline int read(){    int n=0,w=1;register char c=getchar();    while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();}    while(c>='0' && c<='9')n=n*10+c-'0',c=getchar();    return n*w;}const int N=1e5+1,mod=1e9+7;int n,tot,a[N],prime[N],head[N*10];bool notprime[N],vis[N];struct Edge{    int v,nxt;}edge[N<<1];inline void add(int u,int v){edge[++tot]=(Edge){v,head[u]};head[u]=tot;}inline void Get_prime(){    for(int i=2;i<N;++i)    {        if(!notprime[i])            prime[++tot]=i;        for(int j=1;i*prime[j]<=N && j<=tot;++j)        {            notprime[i*prime[j]]=true;            if(i%prime[j] == 0)                break;        }    }}inline void work(int now){    int x=1e5,id=now;    now=a[now];    while(now^1)    {        ++x;        if(now%prime[(int)(x-1e5)]==0)        {            while(now%prime[x]==0)                now/=x;            add(id,x);        }    }}void dfs(int now){    vis[now]=true;    for(int i=head[now];i;i=edge[i].nxt)        dfs(edge[i].v);}inline int ksm(long long x,int b){    long long res=1;    for(;b;b>>=1,x=x*x%mod)        if(b&1)            res=res*x%mod;    return res;}int main(){    freopen("x.in","r",stdin);    freopen("x.out","w",stdout);    int t=read();    Get_prime();    tot=0;    while(t--)    {        memset(vis,false,sizeof vis);        memset(head,0,sizeof head);        tot=0;        n=read();        for(int i=1;i<=n;++i)        {            a[i]=read();            work(i);        }        tot=0;        for(int i=1;i<=n;++i)            if(!vis[i])            {                ++tot;                dfs(i);            }        printf("%d\n",(ksm(2,tot)-2+mod)%mod);    }    fclose(stdin),fclose(stdout);    return 0;}
T2

/* * 這啥題啊。。。 * ao原來d是長度啊。。。。 * * 那不是。。。暴力就很好寫了 * string+map水一發 */#include <string>#include <cstdio>#include <map>inline int read(){    int n=0,w=1;register char c=getchar();    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}    while(c>='0'&&c<='9')n=n*10+c-'0',c=getchar();    return n*w;}const int N=91;int n,m,d,tot,ans,head[N];std::string s;std::map<std::string,int> mp;struct Edge{    int v,w,nxt;}edge[N*(N-1)*2];inline void add(int u,int v,int w){edge[++tot]=(Edge){v,w,head[u]};head[u]=tot;}void dfs(int now,int step){    if(step==d)    {        if(!mp[s])            mp[s]=++ans;        return ;    }    for(int i=head[now];i;i=edge[i].nxt)    {        s.push_back(edge[i].w+'0');        dfs(edge[i].v,step+1);        s.erase(s.end()-1);    }}int main(){    freopen("y.in","r",stdin);    freopen("y.out","w",stdout);    n=read(),m=read(),d=read();    for(int u,v,w,i=1;i<=m;++i)    {        u=read(),v=read(),w=read();        add(u,v,w),add(v,u,w);    }    dfs(1,0);    printf("%d",ans);    fclose(stdin);fclose(stdout);    return 0;}
T3

/* * 我旁邊的dalao用一小時切了這個題,然後到處說:哇T3好水我貪心能100啊 * 然後有人問他:你複雜度多少的 * 他:100啊 * 那人:???100是個什麼複雜度啊,我問的是複雜度 * 他:aoao。。。我看看啊。。。 O(n*q)的 * 那人:。。。你再去看看資料範圍 * 他:??? * * 笑死我了hhhhh * 寫了個類比 */#include <cstdio>inline int read(){    int n=0,w=1;register char c=getchar();    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}    while(c>='0'&&c<='9')n=n*10+c-'0',c=getchar();    return n*w;}const int N=1e5+1;int n,q,x[N];int main(){    freopen("z.in","r",stdin);    freopen("z.out","w",stdout);    n=read(),q=read();    for(int i=1;i<=n;++i)        x[i]=read();    int len,l,r,ans;    while(q--)    {        len=read();        ans=l=0,r=len;        for(int i=1;i<=n;++i)        {            if(x[i]>r)            {                ans+=x[i]-r;                l+=x[i]-r;                r=x[i];            }            else                if(x[i]<l)                {                    ans+=l-x[i];                    r-=l-x[i];                    l=x[i];                }        }        printf("%d\n",ans);    }    fclose(stdin);fclose(stdout);    return 0;}
正解及代碼T1

對所有\(gcd\ne 1\)的兩個數字連邊,最後統計聯通塊數量(假設為\(cnt\)),那麼答案為\(2^{cnt}-2\)

#include<bits/stdc++.h>using namespace std;const int maxn=1e5+10,maxa=1e6+10,mod=1e9+7;int t,n,last[maxa],ans;bool vis[maxn];vector<int> g[maxn];int pcnt,prime[maxa],minp[maxa];bool prm[maxa];inline void init(){    for(int i=2;i<maxa;++i){        if(!prm[i]){            prime[++pcnt]=i;            minp[i]=i;        }        for(int j=1;j<=pcnt&&i*prime[j]<maxa;++j){            prm[i*prime[j]]=true;            minp[i*prime[j]]=prime[j];            if(i%prime[j]==0)                break;        }    }}void dfs(int pos){    vis[pos]=true;    for(int i=0;i<g[pos].size();++i)        if(!vis[g[pos][i]])            dfs(g[pos][i]);}int main(){    freopen("x.in","r",stdin);    freopen("x.out","w",stdout);    init();    scanf("%d",&t);    while(t--){        scanf("%d",&n);        for(int i=1;i<=pcnt;++i)            last[prime[i]]=0;        for(int i=1,x;i<=n;++i){            vis[i]=false;            g[i].clear();            scanf("%d",&x);            while(x>1){                int fac=minp[x];                while(x%fac==0)                    x/=fac;                if(last[fac]){                    g[i].push_back(last[fac]);                    g[last[fac]].push_back(i);                }                last[fac]=i;            }        }        ans=1;        for(int i=1;i<=n;++i)            if(!vis[i])                ans=ans*2%mod,dfs(i);        printf("%d\n",(ans+mod-2)%mod);    }    return 0;}
T2

\(f[i][j][mask]\)表示從\(i\)出發,到\(j\)結束,是否存在一條表示為\(mask\)的路徑

但是顯然這個複雜度不夠優

考慮meet in the middle ,對於每種可能的路徑,枚舉中間的位置進行判斷

\(O(2^{\frac{d}{2}}\times n\times (n+m))+2^d\times n\)

可以用\(bitset\)進行最佳化,能讓整體除以\(64\),由此可以解決\(N\)更大的問題

#include<bits/stdc++.h>using namespace std;const int maxn=90+10,maxmask=1<<20/2+1;int n,m,d,d1,d2,ans;bitset<maxn> g0[maxn],g1[maxn],dp[maxmask],f[maxmask];int main(){    freopen("y.in","r",stdin);    freopen("y.out","w",stdout);    scanf("%d%d%d",&n,&m,&d);    for(int i=1,u,v,c;i<=m;++i){        scanf("%d%d%d",&u,&v,&c);        if(c)            g1[u][v]=g1[v][u]=true;        else            g0[u][v]=g0[v][u]=true;    }    d2=d/2;d1=d-d2;    for(int u=n;u;--u){        for(int i=0;i<maxmask;++i)            dp[i].reset();        dp[1][u]=true;        for(int x=1;x<1<<d1;++x)            for(int v=1;v<=n;++v)                if(dp[x][v]){                    dp[x<<1]|=g0[v];                    dp[x<<1|1]|=g1[v];                }        for(int x=0;x<1<<d1;++x)            f[x][u]=dp[1<<d1|x].any();    }    for(int i=0;i<1<<d1;++i)        for(int j=0;j<1<<d2;++j)            if((dp[1<<d2|j]&f[i]).any())                ++ans;    printf("%d\n",ans);    return 0;}
T3

如果存在一個\(x_i\)使得\(x_{i-1}=x_i\)或者\(x_{i-1}\lt x_i\lt x_{i+1}\),那麼可以刪掉它(當完成上一個\(x\)的時候同時完成了這個任務)

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=1e5+10;int n,m;ll tot,ans[maxn];vector<int> x;vector<pair<int,int> > a;map<int,int> mp;inline ll calc(ll k){    if(!mp.empty()&&mp.begin()->second<0)        return tot-(mp.size()-1)*k;    else        return tot-mp.size()*k;}inline void solve(){    priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;    int t=0;    for(int i=0;i<x.size();++i){        tot+=abs(x[i]);        mp[i]=x[i];        q.push(make_pair(abs(x[i]),i));    }    while(!q.empty()){        int id=q.top().second,tmp=q.top().first;q.pop();        map<int,int>::iterator p=mp.lower_bound(id);        if(p==mp.end()||p->first!=id||abs(p->second)!=tmp)            continue;        while(t<a.size()&&abs(p->second)>a[t].first)            ans[a[t].second]=calc(a[t].first),++t;        if(p!=mp.begin())            if(p!=prev(mp.end())){                tmp=p->second,tot-=abs(p->second);                tmp+=prev(p)->second,tot-=abs(prev(p)->second);                tmp+=next(p)->second,tot-=abs(next(p)->second);                mp.erase(prev(p));                mp.erase(next(p));                p->second=tmp,tot+=abs(tmp);                q.push(make_pair(abs(tmp),id));            }            else{                tot-=abs(p->second);                mp.erase(p);            }        else if(p->second>0)            if(p!=prev(mp.end())){                tmp=p->second,tot-=abs(p->second);                tmp+=next(p)->second,tot-=abs(next(p)->second);                mp.erase(next(p));                if(tmp){                    p->second=tmp,tot+=abs(tmp);                    q.push(make_pair(abs(tmp),id));                }                else                    mp.erase(p);            }            else{                tot-=abs(p->second);                mp.erase(p);            }    }    while(t<a.size())        ans[a[t].second]=calc(a[t].first),++t;}int main(){    freopen("z.in","r",stdin);    freopen("z.out","w",stdout);    scanf("%d%d",&n,&m);    for(int i=0,p,last=0;i<n;++i){        scanf("%d",&p);        if(p==last)            continue;        if(!x.empty()&&(x.back()<0&&p<last||x.back()>0&&p>last))            x.back()+=p-last;        else            x.push_back(p-last);        last=p;    }    for(int i=0,l;i<m;++i){        scanf("%d",&l);        a.push_back(make_pair(l,i));    }    sort(a.begin(),a.end());    solve();    for(int i=0;i<m;++i)        printf("%lld\n",ans[i]);    return 0;}
下午講課:圖題例一

一個\(n\)個點\(m\)條邊的無向連通圖從\(1\)號點開始\(bfs\),可能得到的\(bfs\)序有很多,取決於出邊的訪問順序。現在給出一個\(1\)到\(n\)的排列,判斷是否可能是一個\(bfs\)序

\(n,m\le 2\times 10^5\)

解:

先假設給出的這個\(bfs\)序列是合法的,令每個節點的權值為在給定序列中的位置

然後從\(1\)號點開始進行\(bfs\),出邊的訪問順序按照權值從小到大訪問

最後將這樣跑\(bfs\)得到的\(bfs\)序跟給定的序列進行比較,如果完全一致,那麼這個序列是合法的

例二

一個\(n\)個點\(m\)條邊的無向連通圖中每個點都有一個權值,現在要求給每條邊定一個權值,滿足每個點的權值等於所有相連的邊權之和,權值可負。

解:

如果圖是一棵樹,那麼方案就是唯一的,直接判就可以了。
否則隨便搞一棵產生樹,先不管其他邊,跑一遍。
這時根節點可能還不滿足條件。
這時考慮其他的邊,一條非樹邊會形成一個環。
如果是一個偶環,那麼無論這條非樹邊怎麼變,都不會對根節點產生影響。
而如果是奇環,那麼若給這條非樹邊增加或減少權值,根節點會發生2 的權值變
化。
那麼就可以了。

例三

給定一個\(n\)個點\(m\)條邊的有向帶權圖,對於一條邊權為\(w\)的邊,經過時將獲得\(w\)的收益,之後\(w=\lfloor \frac{w}{2}\rfloor\)

問從\(1\)號點出發最多能獲得多少收益

解:

一個強連通分量內部所有的邊肯定可以被走到底。
所以縮點後\(dp\)即可

例四

有\(m\)個人,\(n\)張椅子,第\(i\)個人只能坐在第\(u_i\)或第\(v_i\)張椅子上。求有多少種方案滿足沒有人坐在同一張椅子上。

解:

把椅子當做點,人當做邊,變成一個圖。
每個連通塊可以分開考慮。
假設某個連通塊中有\(v\)個點,\(e\)條邊,由於連通,有\(v?1\le e\),並且若\(e\gt v\)則無解,所以\(e\)只有\(v?1\)和\(v\)兩種取值。
假如\(e=v?1\),那麼該連通塊有\(v\)種方案:考慮枚舉每個點不放的情況,其他的點都可以唯一確定。
假如\(e=v\)且環長\(\gt 1\),那麼該連通塊有\(2\)種方案:考慮環上的一條邊,這條邊的放法確定後其他的都可以唯一確定。

例五

給定一個\(v\)個點\(e\)條邊的帶權無向圖,在圖上有\(n\)個人,第\(i\)個人位於點\(x_i\),一個人通過一條邊需要花費這條邊的邊權的時間。現在每個人可以自由地走。求最短多少時間後滿足結束後有人的節點數\(\ge m\)

\(n,v\le 500\)

解:

先\(floyd\)預先處理出兩兩之間的距離。
然後可以二分答案。二分答案之後,每個人向能走到的點連邊。
可以發現合法的條件就是最大匹配數\(\ge m\)。
跑二分圖匹配就可以了。

雅禮學習10.4

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.