Loading

noip模拟10

A. 入阵曲

很经典的一道题目,维护具有特殊性质的前缀和,这个方法很常用..其实也是对前缀和特点的一种应用..

本题中维护模 k 相同的前缀和即可..

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define lf double
#define mp make_pair
inline void read(ll &ss)
{
    ss=0; bool cit=0; char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
    while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
    if(cit) ss=-ss;
}
ll n,m,mod,ans;
ll a[500][500];
ll pre[500][500];
ll f[(int)1e7];
ll g[(int)1e7];
signed main()
{
    read(n); read(m); read(mod);
    for(ll i=1;i<=n;i++)
    {
        for(ll j=1;j<=m;j++)
        {
            read(a[i][j]);
            pre[i][j]=(pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+a[i][j]+mod*10)%mod;
        }
    }
    for(ll i=0;i<=n;i++)
    {
        for(ll j=i+1,cnt=0;j<=n;j++,cnt=0)
        {
            f[0]=1;
            for(ll k=1,temp;k<=m;k++)
            {
                temp=(pre[j][k]-pre[i][k]+mod*10)%mod;    
                g[++cnt]=temp;
                ans+=f[temp]; f[temp]++;
            }
            for(ll k=1;k<=cnt;k++) f[g[k]]=0;
        }
    }
    printf("%lld",ans);
    return 0;
}
/*
2 3 2
1 2 1
2 1 2
 */
A_Code

 

B. 将军令

可以考虑树形dp:我们可以很明显地观察到,如果 k 全部都等于 1,那么很像之前做过的一道题《小胖守皇宫》,本题维护一下被 j 级子孙,j 级祖先对自己的影响即可..

另外考虑贪心..我们发现一个性质:无论何时,我们选择 k 级祖先来维护自己是最优的答案。用反证法证明,如果我们选择了比 k 级祖先更低的点来维护自己,那么一定会有更多维护能力被浪费掉,因为 k 级祖先维护的范围才是最广的..

而我考场上只打了一个爆搜,其实加个记忆化就能 A,但是根本想不到,所以这里划重点:打爆搜一定要想想记忆化剪枝

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define lf double
#define mp make_pair
const ll N=1e5+50;
inline void read(ll &ss)
{
    ss=0; bool cit=0; char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
    while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
    if(cit) ss=-ss;
}
ll n,maxn,sp,ans,ts;
ll head[N];
bool vis[N];
struct I { ll u,v,nxt; } a[N*20];
struct II { ll dep,num; } g[N+50];
bool operator <(const II &aa,const II &bb)
{
    if(aa.dep==bb.dep) return aa.num<bb.num;
    return aa.dep<bb.dep;
}
priority_queue<II> que;
inline void add(ll u,ll v)
{
    a[++ts].u=u;
    a[ts].v=v;
    a[ts].nxt=head[u];
    head[u]=ts;
}
ll find(ll now,ll left)
{
    if(left==0 or now==0) return now;
    for(ll i=head[now];i;i=a[i].nxt)
    {
        if(i and g[a[i].v].dep<g[now].dep) return find(a[i].v,left-1);
    }
}
void dfs_depth(ll now,ll depth)
{
    vis[now]=true;
    g[now].num=now; g[now].dep=depth;
    que.push(g[now]);
    for(ll i=head[now];i;i=a[i].nxt)
    {
        if(vis[a[i].v]) continue;
        dfs_depth(a[i].v,depth+1);
    }
    return ;
}
void dfs(ll dad,ll now,ll left)
{
    vis[now]=true;
    if(left==0 or now==0) return ;
    for(ll i=head[now];i;i=a[i].nxt)
    {
        if(a[i].v==dad) continue;
        dfs(now,a[i].v,left-1);
    }
    return ;
}
signed main()
{
    read(n); read(maxn); read(sp);
    ll u,v;
    for(ll i=1;i<=n-1;i++)
    {
        read(u); read(v);
        add(u,v); add(v,u);
    }
    dfs_depth(1,1);
    memset(vis,0,sizeof vis);
    II temp; ll tem;
    while(!que.empty())
    {
        temp=que.top(); que.pop();
        if(vis[temp.num]) continue; ans++;
        tem=find(temp.num,maxn); dfs(tem,tem,maxn);
    }
    printf("%d",ans);
    return 0;
}
B_Code

 

C. 星空

又是一道观察性质的题目..(大概是因为我太菜,一到这类题就只能认为是观察性质,怎么想都想不到..)

观察 k 的范围,理应想到状压..

然后考虑题目的特点:发现可以类比’开心消消乐‘..(题解里面还管这个叫广义前缀和,不过想一想还真的是有用到前缀和的特点..)

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define lf double
#define mp make_pair
const ll N=1e5+50;
inline void read(ll &ss)
{
    ss=0; bool cit=0; char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
    while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
    if(cit) ss=-ss;
}
ll n,m,t,ts;
bool p[N],g[N],vis[N];
ll op[N],pos[N],org[N];
ll head[N],f[1<<20];
ll dis[200][N];
deque<ll> que;
inline void bfs(ll now)
{
    dis[now][pos[now]]=0;
    que.push_back(pos[now]);
    vis[pos[now]]=1; ll x,y;
    while(que.size())
    {
        x=que.front();
        que.pop_front();
        for(ll i=1;i<=t;i++)
        {
            y=x-op[i];
            if(y>0 and dis[now][y]>dis[now][x]+1)
            {
                dis[now][y]=dis[now][x]+1;
                que.push_back(y); vis[y]=1;
            }
            y=x+op[i];
            if(y<=n+1 and dis[now][y]>dis[now][x]+1)
            {
                dis[now][y]=dis[now][x]+1;
                que.push_back(y); vis[y]=1;
            }
        }
        vis[x]=0;
    }
    return ;
}
signed main()
{
    read(n); read(m); read(t);
    ll temp; memset(p,1,sizeof p);
    for(ll i=1;i<=m;i++)
    {
        read(temp); p[temp]=false;
    }
    for(ll i=1;i<=t;i++) read(op[i]);
    sort(op+1,op+1+t);
    temp=0; p[0]=true;
    for(ll i=1;i<=n+1;i++)
    {
        g[i]=p[i] xor p[i-1];
        if(g[i]) pos[++temp]=i,org[i]=temp;
    }
    memset(dis,0x3f,sizeof dis);
    memset(f,0x3f,sizeof f);
    for(ll i=1;i<=temp;i++) bfs(i);
    f[(1<<temp)-1]=0;
    for(ll i=(1<<temp)-1,j,v;i>=0;i--)
    {
        j=1;
        while(((1<<(j-1)) & i)==0 and j<temp) j++;
        for(ll k=j+1;k<=temp;k++)
        {
            if((i & (1<<(k-1)))==0) continue;
            v=(i xor (1<<(j-1))) xor (1<<(k-1));
            f[v]=min(f[v],f[i]+dis[j][pos[k]]);
        }
    }
    printf("%d",f[0]);
    return 0;
}
/*
5 2 2
1 5
3 4

 */
C_Code

 

posted @ 2021-07-18 19:50  AaMuXiiiiii  阅读(26)  评论(0编辑  收藏  举报