NOIP 模擬 七十一


最后一場多校模擬賽,好像是信心賽??

100+100+20+40=260

T1 簽到題(qiandao)

如果一個點的度數不是 c 的倍數,那么它的貢獻至少為 1。我們一定可以構造出一種方案,使得度數是 c 的倍數的點的貢獻為 0,其余的點的貢獻為 1。這可以簡單網絡流證明,留給讀者練習。

整了會這個二分圖,推了好多個例子,貌似按照上面的說法都能調整出來。然后嘗試着打了這10行代碼,大樣例一發帶過。心里還是很虛但是並不會其他辦法。現在正在嘗試證明。

#include<bits/stdc++.h>
#define N 1000500
using namespace std;
int c,k,n,m,du1[N],du2[N],ans;
signed main()
{   freopen("qiandao.in","r",stdin);
    freopen("qiandao.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&k,&c);
    for(int i=1;i<=k;++i)
    {   int u,v;scanf("%d%d",&u,&v);
        ++du1[u];++du2[v];
    }
    for(int i=1;i<=n;++i)if(du1[i]%c)++ans;
    for(int i=1;i<=m;++i)if(du2[i]%c)++ans;
    printf("%d\n",ans);
}

T2 M 弟娃(magic)

考慮對於一對點,將哪些點作為根會使這對點產生貢獻。現在假定 1 為實際根,分兩種情況:若這兩個點不是祖先兒子關系,則將根選在兩個點的子樹里時,這對點會產生貢獻;若這兩個點是祖先兒子關系,令深度較深的點為 x,較淺的為 y,y 在這條鏈上的兒子為 z,則將根選在 x 的子樹里,或是不在 z 的子樹里時,這對點會產生貢獻。求出 dfs 序,相當於我們只需要支持區間加,全局 max 即可。

這題讀完題基本上就會了,但是思路上一個小細節調了會。

#include<bits/stdc++.h>
#define N 300500
using namespace std;
inline int read()
{   int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,q,head[N],dep[N],top[N],siz[N],fa[N],dfn[N],son[N],tot,cnt,f[N][18];
const int jie=17;
struct jj
{int to,nxt;}bian[N<<1];
struct segment_Tree
{int tag,maxn;}tree[N<<2];
inline void add(int u,int v)
{   bian[++tot].to=v;
    bian[tot].nxt=head[u];
    head[u]=tot;
}
void dfs1(int x,int ff)
{   fa[x]=f[x][0]=ff;son[x]=-1;siz[x]=1;dep[x]=dep[ff]+1;dfn[x]=++cnt;
    for(int i=1;i<=jie and f[x][i-1];++i)f[x][i]=f[f[x][i-1]][i-1];
    for(int i=head[x];i;i=bian[i].nxt)
    {   int v=bian[i].to;
        if(v==ff)continue;
        dfs1(v,x);
        siz[x]+=siz[v];
        if(son[x]==-1 or siz[son[x]]<siz[v])son[x]=v;
    }
}
inline int LCA(int x,int y)
{   if(dep[x]<dep[y])swap(x,y);
    for(int i=jie;i>=0;--i)if(dep[f[x][i]]>=dep[y])x=f[x][i];
    if(x==y)return x;
    for(int i=jie;i>=0;--i)
    if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return fa[x];
}
inline int get(int x,int y)
{   for(int i=jie;i>=0;--i)if(dep[f[y][i]]>dep[x])y=f[y][i];
    return y;
}
#define int register int 
inline void pushup(int x)
{tree[x].maxn=max(tree[x<<1].maxn,tree[x<<1|1].maxn);}
inline void pushdown(int x)
{   tree[x<<1].maxn+=tree[x].tag;
    tree[x<<1].tag+=tree[x].tag;
    tree[x<<1|1].maxn+=tree[x].tag;
    tree[x<<1|1].tag+=tree[x].tag;
    tree[x].tag=0;
}
void update(int x,int l,int r,int L,int R,int val)
{   if(l>=L and r<=R)
    {   tree[x].maxn+=val;
        tree[x].tag+=val;
        return ;
    }
    if(tree[x].tag!=0)pushdown(x);
    int mid=(l+r)>>1;
    if(mid<R)update(x<<1|1,mid+1,r,L,R,val);
    if(mid>=L)update(x<<1,l,mid,L,R,val);
    pushup(x);
}
signed main()
{   freopen("magic.in","r",stdin);
    freopen("magic.out","w",stdout);
    n=read();q=read();
    for(int i=1;i<n;++i)
    {   int u,v;
        u=read();v=read();
        add(u,v);add(v,u);
    }
    dfs1(1,0);
    for(int i=1;i<=q;++i)
    {   int x,y;
        x=read();y=read();
        int lca=LCA(x,y);
        if(x==y)update(1,1,n,1,n,1);
        else
        if(lca==x)
        {   
            update(1,1,n,dfn[y],dfn[y]+siz[y]-1,1);
            update(1,1,n,1,n,1);
            int del=get(x,y);
            update(1,1,n,dfn[del],dfn[del]+siz[del]-1,-1);
        }
        else
        if(lca==y)
        {   update(1,1,n,dfn[x],dfn[x]+siz[x]-1,1);
            update(1,1,n,1,n,1);
            int del=get(y,x);
            update(1,1,n,dfn[del],dfn[del]+siz[del]-1,-1);
        }
        else
        {   update(1,1,n,dfn[x],dfn[x]+siz[x]-1,1);
            update(1,1,n,dfn[y],dfn[y]+siz[y]-1,1);
        }
        printf("%d\n",tree[1].maxn);
    }   
}

T3 變異大老鼠(arrest)

考慮 SPT 上樹形 dp。fi,j 表示在以 i 為根的子樹中,總共放了 j 個警察,逮捕到楊吞天的最大概率。枚舉當前節點放幾個警察正常樹形 dp 轉移。

難度判斷錯誤,讀題忽略了路徑唯一,自己把題目想復雜了,其實就是個背包。


#include<bits/stdc++.h>
using namespace std;
int dis[310][310],n,m,num,tong[310][310],cnt;
double gai[310],ans[310][310],dp[310][310],tmp[310][310],lst,lin[310][310],base[310][310],ds[310];
vector<int>p[310],pp[310];
bool vis[310];
inline void dfs(int x,int fa)
{   for(int i=1;i<=num;++i)dp[x][i]=ans[x][i];
    for(int i=0;i<=num;++i)tmp[x][i]=0;
    for(auto i:pp[x])
    {   dfs(i,x);
        for(int j=0;j<=num;++j)lin[x][j]=tmp[x][j];
        for(int k=0;k<=num;++k)for(int j=0;j+k<=num;++j)lin[x][j+k]=max(lin[x][j+k],tmp[x][j]+dp[i][k]);
        for(int j=0;j<=num;++j)tmp[x][j]=lin[x][j];
    }
    if(pp[x].size())
    {
    for(int i=0;i<=num;++i)lin[x][i]=dp[x][i];
    for(int i=0;i<=num;++i)for(int j=0;j+i<=num;++j)lin[x][i+j]=max(lin[x][i+j],dp[x][i]+(1-ans[x][i])*tmp[x][j]/(1.0*pp[x].size()));
    for(int i=0;i<=num;++i)dp[x][i]=lin[x][i];
    }
}
signed main()
{   freopen("arrest.in","r",stdin);
    freopen("arrest.out","w",stdout);
    memset(dis,0x3f3f3f3f,sizeof(dis));
    memset(base,0x3f3f3f3f,sizeof(base));
    scanf("%d%d%d",&n,&m,&num);
    for(int i=1;i<=m;++i)
    {   int u,v,w;scanf("%d%d%d",&u,&v,&w);
        dis[u][v]=dis[v][u]=base[u][v]=base[v][u]=min(dis[u][v],w);
        if(u!=v)tong[u][v]=tong[v][u]=1,p[u].push_back(v),p[v].push_back(u);
    }
    for(int i=1;i<=n;++i)
    {   dis[i][i]=0;base[i][i]=0;
        for(int j=1;j<=num;++j)scanf("%lf",&ans[i][j]);
    }
    for(int k=1;k<=n;++k)
    for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j)
    if(i!=j and j!=k and i!=k and dis[i][j]>dis[i][k]+dis[k][j])
    {   dis[i][j]=dis[j][i]=dis[i][k]+dis[k][j];
    }
    gai[1]=1;for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)if(dis[1][j]+base[i][j]==dis[1][i] and i!=j and tong[i][j])
    {   if(j==1 and base[i][j]!=dis[i][j])continue;
        pp[j].push_back(i);  
    }
    dfs(1,0);
    for(int i=0;i<=num;++i)lst=max(lst,dp[1][i]);
    printf("%.6lf\n",lst);
}

T4 朝鮮時蔬(vegetable)

玄學,每個點解法不同。

#include<bits/stdc++.h>
#define int long long
#define mod 1000000007
#define inv12 83333334
using namespace std;
int n,m,k,ans=1;
inline int qpow(int a,int b)
{   int base=1;
    while(b)
    {   if(b&1)base=base*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return base;
}
inline int pow1(int x){return x%mod*((x+1)%mod)%mod*(2*x%mod+1)%mod;}
signed main()
{   freopen("vegetable.in","r",stdin);
    freopen("vegetable.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k);
    if(m==k)
    {   for(int i=1;i<=k;++i)ans=ans*((n-i+1)%mod)%mod;
        for(int i=k;i;--i)ans=ans*qpow(i,mod-2)%mod;
        printf("%lld\n",ans);return 0;
    }
    if(m==2 and k==1)
    {   ans=0;
        for(int l=1,r;l<=n;l=r+1)
        {   r=n/(n/l);
            ans=(ans+((r-l+1)%mod)*(n/l%mod)%mod)%mod;
        }
        printf("%lld\n",(ans-n%mod+mod)%mod);return 0;
    }
    if(m==3 and k==1){printf("%lld\n",(n/3)%mod);return 0;}
    if(m==4 and k==1)
    {   if(n<=5)printf("%lld\n",1ll);
        else  
        {   ans=0;for(int i=2;i<=7;++i)
            {   if(i==6)continue;
                ans=(ans+n/(3*i))%mod;
            }ans=(ans+n/10)%mod;
            printf("%lld\n",ans);
        }
        return 0;
    }
    if(m==4 and k==2)
    {   if(n<=6)cout<<1<<endl;
        if(n==7)cout<<3<<endl;
        if(n==8)cout<<6<<endl;
        if(n==9)cout<<9<<endl;
        if(n==10)cout<<10<<endl;
        if(n>=11)cout<<(n/11+n/29)%mod<<endl;
        return 0;
    }
    if(m==3 and k==2)
    {   ans=0;
        for(int l=1,r;l<=n;l=r+1)
        {   r=n/(n/l);int tmp=0;
            int zhi1=(l-1)/2,zhi2=(r-1)/2;
            if(!(l&1))tmp=(tmp+zhi1)%mod,zhi1++;
            if(r&1)tmp=(tmp+zhi2)%mod,--zhi2;
            if(zhi1<=zhi2)
            tmp=(tmp+(zhi1+zhi2)%mod*((zhi2-zhi1+1)%mod)%mod)%mod;
            ans=(ans+tmp*(n/l%mod)%mod)%mod;
        }
        printf("%lld\n",ans);return 0;
    }
    if(m==4 and k==3)
    {   ans=0;
        for(int l=1,r;l<=n;l=r+1)
        {   r=n/(n/l);int tmp=0;
            tmp=(tmp+(pow1(r)-pow1(l-1)+mod)%mod*inv12%mod*2%mod)%mod;
            tmp=(tmp-((l+r)%mod)*((r-l+1)%mod)%mod*inv12%mod*6%mod*6%mod+mod)%mod;
            tmp=(tmp+(r-l+1)%mod*5%mod)%mod;
            tmp=(tmp+((r/2)-(l+1)/2+1)%mod*3%mod)%mod;
            tmp=(tmp+(r/3-(l+2)/3+1)%mod*4%mod)%mod;
            tmp=tmp*inv12%mod;
            ans=(ans+tmp*((n/l)%mod)%mod)%mod;
        }
        if(n==4)ans=1;if(n==5)ans=5;
        printf("%lld\n",ans);return 0;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM