10 29

  頹了好幾天的blog 應該寫寫了 畢竟有些題目仍是很不錯的關鍵是dp 每次都推不出來 果真仍是我太菜了.ios

今天 考的是牛客的比賽 質量還行 不過時望的分220 實際得分180/cy 好多神仙AK 各類崩潰 dp推不出來 圖論不會寫 很自閉反正... T1 100 T2 40 T3 40c++

LINK:簡單博弈問題數組

這道題就頗有意思了 典型的博弈問題 多個局面 考慮有向圖遊戲的和求SG函數 對於一個局面不一樣的石子個數不一樣 沒有任何關係 仔細分析每個局面。網絡

對於1 必勝局 對於2 必敗局 對於3 必敗局...好像沒什麼規律 考慮偶數和奇數分開來看 偶數 咱們後手是始終貼着先手下 能夠發現只有先手不能走 因此偶數局面先手必敗。ide

考慮大於1 的奇數局面 咱們後手 的第一步下在先手第一步的棋子旁邊的旁邊 此時先手有兩個位置不能下 然後手只有一個位置不能下 以後繼續貼着先手下 能夠發現仍是先手敗了 儘管能多下一個位置可是 被第一步反了一個位置造成相似於偶數的局面此時仍是先手先下。函數

因此獲得SG函數 除了1這個局面 其他全部局面都是0 而後求有向圖遊戲的和便可。測試

//單個局面偶數必敗
//以爲單個局面除了1 剩下也是必敗 直接異或好了
//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db double
#define pii pair<ll,ll>
#define mk make_pair
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
int T;
int n,ans;
int main()
{
    T=read();
    while(T--)
    {
        ans=0;
        n=read();
        for(int i=1;i<=n;++i)
        {
            int x=read();
            if(x==1)ans^=1;
        }
        if(ans)puts("rabbit");
        else puts("hamster");
    }
    return 0;
}
View Code

 兩個mingw 一遍補模擬賽的題目一遍寫其餘題目畢竟考了就要補。優化

LINK:樹形dp問題 spa

這道題仍是很不錯的引出了樹上dp經常使用的兩個方法 換根dp 和 up and down 都挺常見的 不過我最經常使用的是換根 這道題我決定兩種方法都寫一下。3d

首先是第一問 求以任意一個點爲根的 深度不超過k的兒子的個數. 先考慮第一種比較不熟悉的方法 up and down。

1 預處理 設 f[i][j] 表示以i爲根的子樹內小於k的深度的點的個數。w[i][j]表示i向上j層的點數 

2 預處理 設g[i][j]表示以i爲根的子樹內小於k的深度點的乘積不包括其自己 c[i][j]表示向上的不超過j的點的乘積 不包括其自己。

處理好以後 發現答案就有了/cy 轉移挺難寫的 一道很是有實際意義的題目。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define INF 1000000000
#define ll long long
#define db double
#define pb push_back
#define un unsigned
#define mod 1000000007
#define ull unsigned long long
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=100010;
int n,k,len;
int f[MAXN][11];//f[i][j]表示以i爲根的子樹內小於等於j的點的個數.
int w[MAXN][11];//w[i][j]表示從i向上深度爲不超過j的點的個數
ll g[MAXN][11];//g[i][j]表示以i爲根的子樹內部深度小於等於j的點的乘積 不包含其自己
ll c[MAXN][11];//c[i][j]表示從i向上深度不超過j的點的乘積 不包含其自己
int lin[MAXN],nex[MAXN<<1],ver[MAXN<<1];
inline void add(int x,int y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
inline ll fast_pow(ll b,ll p)
{
    ll ans=1;
    while(p)
    {
        if(p&1)ans=ans*b%mod;
        b=b*b%mod;
        p=p>>1;
    }
    return ans;
}
inline void dfs(int x,int father)
{
    for(int i=0;i<=k;++i)f[x][i]=1;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(tn==father)continue;
        dfs(tn,x);
        for(int j=1;j<=k;++j)f[x][j]+=f[tn][j-1];
    }
}
inline void dfs1(int x,int father)
{
    for(int i=0;i<=k;++i)g[x][i]=1;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(tn==father)continue;
        dfs1(tn,x);
        for(int j=1;j<=k;++j)g[x][j]=g[x][j]*g[tn][j-1]%mod*f[tn][j-1]%mod;
    }
}
inline void dp(int x,int father)
{
    for(int i=0;i<=k;++i)w[x][i]+=1;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(tn==father)continue;
        for(int j=1;j<=k;++j)
        {
            w[tn][j]+=w[x][j-1];
            if(j>=2)w[tn][j]+=f[x][j-1]-1-f[tn][j-2];
        }
        dp(tn,x);
    }
}
inline void dp1(int x,int father)
{
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(tn==father)continue;
        for(int j=1;j<=k;++j)
        {
            c[tn][j]=c[tn][j]*c[x][j-1]%mod*g[x][j-1]%mod;
            if(j>=2)
            {
                c[tn][j]=c[tn][j]*(w[x][j-1]+f[x][j-1]-1-f[tn][j-2])%mod;
                c[tn][j]=c[tn][j]*fast_pow(g[tn][j-2],mod-2)%mod;
                c[tn][j]=c[tn][j]*fast_pow(f[tn][j-2],mod-2)%mod;
            }
        }
        dp1(tn,x);
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();k=read();
    for(int i=1;i<n;++i)
    {
        int x,y;
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dfs(1,0);
    //求出以某個點爲根的深度不超過j的點的個數.
    dp(1,0);
    //for(int i=1;i<=n;++i)printf("%d ",f[i][k]);
    //for(int i=1;i<=n;++i)printf("%d ",w[i][k]);
    for(int i=1;i<=n;++i)printf("%d ",f[i][k]+w[i][k]-1);
    puts("");
    dfs1(1,0);
    //求出以某個點位根的深度不超過j的點的個數.
    for(int i=1;i<=n;++i)for(int j=0;j<=k;++j)c[i][j]=1;
    dp1(1,0);
    //for(int i=1;i<=n;++i)printf("%d ",g[i][k]);
    //for(int i=1;i<=n;++i)printf("%d ",c[i][k]);
    for(int i=1;i<=n;++i)printf("%lld ",c[i][k]*g[i][k]%mod*(f[i][k]+w[i][k]-1)%mod);
    return 0;
}
View Code

發現遇到這類問題很是的膽怯 好像是不敢去思考 這類問題我想應該不難只是本身懶的想這種私下跟實際上是不可取的qwq。

首先 每張牌有兩種選擇 而後顯然是一個二分圖的問題 沒多想直接暴力網絡流了 加上測試點4的前綴和處理能夠獲得40分。

考慮滿分作法 咱們發現 一個事情 其實也能夠選擇匈牙利直接二分圖的最大匹配。複雜度qn^2 咱們能夠順勢優化這個東西。

對於一個左端點 必定 有一個與之對應能表示出來的最大的右端點 而後左端點移動的同時右端點也同時移動 咱們預處理這個東西 而後O(1) 回答詢問便可。

複雜度n^2+Q 實測可過 緣由 跑不滿的緣故 咱們由此想到用網絡流優化這個過程複雜度能夠達到nsqrt(n);

可實際上 網絡流更換匹配的過程很是的複雜還須要修改一條流這個是很難作到的 因此基本上很難優化。固然直接匈牙利修改好修改 並且必定跑不滿因此夢想匈牙利就過去了。

考慮真正的滿分作法。這其實是一個圖論的問題 考慮每一張牌把兩個花色連了起來 咱們抽象成 幾個連通塊。

能夠發現若是聯通塊是一顆樹那麼這棵樹 這幾個節點都不能被同時體現。考慮一下詢問  一個詢問的不合法當且僅當其包含了一棵完整的樹。

這樣的話 如何判斷一條線段包含了 這樣的一棵樹 顯然 對於一棵樹儘管多是不連續的 可是 判斷包含關係只須要 找到樹的編號的最大值及最小值這個線段包含樹的兩端便可。

那麼 就是 一個經典問題了 線段之間的覆蓋問題。 顯然 咱們離線一下利用樹狀數組便可。複雜度mlogn.

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db double
#define pii pair<ll,ll>
#define mk make_pair
#define mod 1000000007
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=100010;
int n,m,len,minn,maxx;
int q[MAXN],f[MAXN],vis[MAXN],c[MAXN],ans[MAXN],top;
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
inline void add(int x,int y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
inline int getfather(int x){return x==f[x]?x:f[x]=getfather(f[x]);}
inline void dfs(int x,int father)
{
    maxx=max(maxx,x);
    minn=min(minn,x);
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(tn==father)continue;
        dfs(tn,x);
    }
}
struct wy
{
    int x,y;
    int id;
    int friend operator <(wy a,wy b)
    {
        return a.x<b.x;
    }
}t[MAXN],w[MAXN];
inline void add1(int x,int y)
{
    while(x<=n)
    {
        c[x]+=y;
        x+=x&(-x);
    }
    return;
}
inline int ask(int x)
{
    int cnt=0;
    while(x)
    {
        cnt+=c[x];
        x-=x&(-x);
    }
    return cnt;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;++i)f[i]=i;
    for(int i=1;i<=m;++i)
    {
        int x,y;
        x=read();y=read();
        add(x,y);add(y,x);
        int xx=getfather(x);
        int yy=getfather(y);
        if(xx==yy)vis[xx]=1;
        f[xx]=yy;
    }
    for(int i=1;i<=n;++i)
    {
        int x=getfather(i);
        if(vis[x])continue;
        q[++top]=i;
        vis[x]=1;
    }
    //for(int i=1;i<=top;++i)printf("%d\n",q[i]);
    for(int i=1;i<=top;++i)
    {
        minn=INF,maxx=0;
        dfs(q[i],0);
        w[i]=(wy){minn,maxx};
        add1(maxx,1);
    }
    m=read();
    for(int i=1;i<=m;++i)
    {
        int x,y;
        x=read();y=read();
        t[i]=(wy){x,y,i};
    }
    sort(t+1,t+1+m);
    sort(w+1,w+1+top);
    int flag=1;
    for(int i=1;i<=m;++i)
    {
        while(flag<=top&&w[flag].x<t[i].x)
        {
            add1(w[flag].y,-1);
            ++flag;
        }
        ans[t[i].id]=ask(t[i].y);
    }
    for(int i=1;i<=m;++i)puts(ans[i]?"No":"Yes");
    return 0;
}
View Code
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息