Loading

noip模拟6

T1 辣鸡

考时操作

盲打暴力+剪枝优化..

然后自以为看到了数据范围 1e9 之后还写了一个亿进制的高精度..

结果人家数据水得一批..

直接原地跳楼..

考后反思

就是一个排序优化+暴力..

这里的排序就是为了免得无效访问过多..

学会剪枝加暴力..全家省队没问题..

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define re register ll
#define mp make_pair
const ll N=100050;
inline void read(ll &ss)
{
    ss=0;
    ll cit=0;
    char ch;
    ch=getchar();
    while((ch>'9') or (ch<'0'))
    {
        if(ch=='-') cit=1;
        ch=getchar();
    }
    while((ch<='9') and (ch>='0'))
    {
        ss=(ss<<3)+(ss<<1)+(ch^48);
        ch=getchar();
    }
    if(cit) ss=-ss;
}
ll n;
ll sum;
struct Square
{
    ll x,y;
    ll x2,y2;
}a[N];
inline bool cmp(Square aa,Square bb)
{
    if(aa.x==bb.x) return aa.y<bb.y;
    return aa.x<bb.x;
}
inline void Work_1(ll i,ll j)
{
/*    if(a[i].x==a[j].x)
    {
        if(a[i].x2=a[j].x2)
        {
            sum+=(a[i].x2-x[i].x)*2;
        }
        else sum+=min(a[i].x2-a[i].x,a[j].x2-a[j].x)*2+1;
        return ;
    }    
*/
    if(a[i].y2==a[j].y-1 or a[i].y==a[j].y2+1)
    {
        sum+=(min(a[i].x2,a[j].x2)-a[j].x+1)*2;
        if(a[i].x==a[j].x) --sum;
        if(a[i].x2==a[j].x2) --sum;
    }
    return ;
}
inline void Work_2(ll i,ll j)
{
    if(a[i].y>a[j].y2+1 or a[i].y2<a[j].y-1) 
    {    
        return ;
    }
    if(a[i].y2==a[j].y-1 or a[i].y==a[j].y2+1)
    {
        ++sum;
        return ;
    }
    if(a[i].y2==a[j].y2 and a[i].y!=a[j].y) 
    {
        sum+=min(a[i].y2-a[i].y,a[j].y2-a[j].y)*2+1;
        return ;
    }
    if(a[i].y2!=a[j].y2 and a[i].y==a[j].y) 
    {
        sum+=min(a[i].y2-a[i].y,a[j].y2-a[j].y)*2+1;
        return ;
    }
    if(a[i].y2<a[j].y2 and a[i].y>a[j].y) 
    {    
        sum+=(a[i].y2-a[i].y+1)*2;
        return ;
    }
    if(a[i].y2>a[j].y2 and a[i].y<a[j].y) 
    {
        sum+=(a[j].y2-a[j].y+1)*2;
        return ;
    }
    if(a[i].y2==a[j].y2 and a[i].y==a[j].y) 
    {
        sum+=(a[i].y2-a[i].y)*2;
        return ;
    }
    if(a[i].y2<a[j].y2 and a[i].y<a[j].y)
    {
        sum+=(a[i].y2-a[j].y+1)*2;
        return ;
    }
    if(a[i].y2>a[j].y2 and a[i].y>a[j].y)
    {
        sum+=(a[j].y2-a[i].y+1)*2;
        return ;
    }
}

signed main()
{
    read(n);
    for(re i=1;i<=n;++i)
    {
        read(a[i].x);
        read(a[i].y);
        read(a[i].x2);
        read(a[i].y2);
        sum+=(a[i].x2-a[i].x)*(a[i].y2-a[i].y)*2;
    }
    sort(a+1,a+1+n,cmp);
    for(re i=1;i<=n;++i)
    {
        for(re j=i+1;j<=n;++j)
        {
            if(a[j].x>a[i].x2+1) break;
            if(a[j].x<=a[i].x2) Work_1(i,j);
            if(a[j].x==a[i].x2+1) Work_2(i,j);
            //cout<<i<<" "<<j<<" "<<sum<<endl;
        }
    }
    printf("%lld",sum);
    return 0;
}
T1 code

 

 

T2 模板

考时操作

我只能说我没学过启发式合并..

而且我的代码写了一个和内置函数名重名的变量..

所以再次斩获 0pts..

 

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define lf double
#define mp make_pair
const ll N=2e5+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,ts;
ll head[N],siz[N],fa[N],son[N],s[N];
ll lct[N],col[N],lsh[N];
ll tim[N],ans[N];
struct I { ll u,v,nxt; } a[N*2];
struct II { ll l,r,sum,bs,lazy; } tr[N*4];
// 线段树维护的是某个时间的各个属性..
vector<pair<ll,ll> > vec[N];
void add(ll u,ll v)
{
    a[++ts].u=u;
    a[ts].v=v;
    a[ts].nxt=head[u];
    head[u]=ts;
}
void spread(ll x)
{
    //lazy 用来明确是否需要清空子孙,一个小的优化..
    if(tr[x].lazy)
    {
        tr[x<<1].sum=0;
        tr[(x<<1)|1].sum=0;
        tr[x<<1].bs=0;
        tr[(x<<1)|1].bs=0;
        tr[x<<1].lazy=1;
        tr[(x<<1)|1].lazy=1;
        tr[x].lazy=0;
    }
    return ;
}
void update(ll x,ll pos,ll val,ll num)
{
    if(tr[x].l==tr[x].r)
    {
        tr[x].sum+=val;//颜色种类个数
        tr[x].bs+=num;//小球个数
        return ;
    }
    spread(x);
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(pos<=mid) update(x<<1,pos,val,num);
    else update((x<<1)|1,pos,val,num);
    tr[x].sum=tr[x<<1].sum+tr[(x<<1)|1].sum;
    tr[x].bs=tr[x<<1].bs+tr[(x<<1)|1].bs;
    return ;
}
void ins(ll x)
{
    ll u,v;
    for(ll i=0;i<vec[x].size();i++)
    {
        u=vec[x][i].first,v=vec[x][i].second; // 颜色 时间
        // 由于对时间的上移,所以可以保证不会被颜色种类被算重..
        if(!tim[u]) 
        {
            update(1,v,1,1);
            tim[u]=v;
        }
        else
        {
            if(tim[u]>v)
            {
                update(1,tim[u],-1,0);
                update(1,v,1,1); tim[u]=v;
            }
            else update(1,v,0,1);
        }
    }
    return ;
}
ll ask(ll x,ll much)
{
    if(much==0) return 0;
    if(tr[x].bs<=much) return tr[x].sum;
    spread(x);                    
    if(much<=tr[x<<1].bs) return ask(x<<1,much);
    else return tr[x<<1].sum+ask((x<<1)|1,much-tr[x<<1].bs);
}
void dfs1(ll now,ll dad)
{
    fa[now]=dad; siz[now]=vec[now].size();
    for(ll i=head[now];i;i=a[i].nxt)
    {
        if(a[i].v==dad) continue;
        dfs1(a[i].v,now); siz[now]+=siz[a[i].v];
        if(siz[a[i].v]>siz[son[now]]) son[now]=a[i].v;
        // 根据颜色个数分布重儿子..
    }
    return ;
}
void clear(ll x)
{
    ll u;
    tr[1].sum=0; tr[1].bs=0; tr[1].lazy=1;
    for(ll i=0;i<vec[x].size();i++)
    {
        u=vec[x][i].first; tim[u]=0; 
        //不使用memset,从而达到一个不止于优化的优化..
    }
    return ;
}
void dfs2(ll now,ll dad)
{
    //始终让重儿子的数值位于树中,又是一把优化,即上文不使用memset的原因之一..
    for(ll i=head[now];i;i=a[i].nxt)
    {
        if(a[i].v==dad or a[i].v==son[now]) continue;
        dfs2(a[i].v,now); clear(a[i].v);
    }
    if(son[now]) dfs2(son[now],now);
    ins(now);
    for(ll i=head[now];i;i=a[i].nxt)
    {
        if(a[i].v==dad or a[i].v==son[now]) continue;
        ins(a[i].v);
    }
    ans[now]=ask(1,s[now]); 
    if(son[now])
    {
        for(ll i=0;i<vec[now].size();i++)
        {
            vec[son[now]].push_back(vec[now][i]);
        }
        vec[now].clear();
        swap(vec[now],vec[son[now]]);
        for(ll i=head[now];i;i=a[i].nxt)
        {
            if(a[i].v==dad or a[i].v==son[now]) continue;
            for(ll j=0;j<vec[a[i].v].size();j++)
            {
                vec[now].push_back(vec[a[i].v][j]);
            }
            vec[a[i].v].clear();
        }
    }
    return ;
}
void build(ll x,ll l,ll r)
{
    tr[x].l=l; tr[x].r=r;
    if(l==r) return ;
    ll mid=(l+r)>>1;
    build(x<<1,l,mid); build((x<<1)|1,mid+1,r);
    return ;
}
signed main()
{
    read(n);
    ll u,v,sum;
    for(ll i=1;i<=n-1;i++)
    {
        read(u); read(v);
        add(u,v); add(v,u);
    }
    for(ll i=1;i<=n;i++) read(s[i]);
    read(m);
    for(ll i=1;i<=m;i++)
    {
        read(lct[i]); read(col[i]);
        lsh[i]=col[i];
    }
    build(1,1,m);
    sort(lsh+1,lsh+1+m);
    sum=unique(lsh+1,lsh+1+m)-lsh-1;
    for(ll i=1;i<=m;i++)
    {
        col[i]=lower_bound(lsh+1,lsh+1+sum,col[i])-lsh;
        vec[lct[i]].push_back(mp(col[i],i));
    }
    dfs1(1,0); memset(siz,0,sizeof siz);
    dfs2(1,0);
    read(m);
    for(ll i=1;i<=m;i++)
    {
        read(u);
        printf("%d\n",ans[u]);
    }
    return 0;
}
T2 Code

 

 

T3 大佬

考时操作

我选择了深搜..可是深搜没有选择我..

 
考后反思

这是一道方法多种多样的题目..

组合数..递推..等等..

这里转下学长的博客 --skyh

套中套..

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define re register ll
const ll mod=1000000007;
inline void read(ll &ss)
{
    ss=0;
    ll cit=0;
    char ch;
    ch=getchar();
    while((ch>'9') or (ch<'0'))
    {
        if(ch=='-') cit=1;
        ch=getchar();
    }
    while((ch<='9') and (ch>='0'))
    {
        ss=(ss<<3)+(ss<<1)+(ch^48);
        ch=getchar();
    }
    if(cit) ss=-ss;
}
ll n;
ll m;
ll k;
ll val[2000000];
ll ans;
inline ll mont(ll a,ll b,ll c)
{
    ll temp=1;
    a=a%c;
    while(b>0)
    {
        if(b&1) temp=(temp*a)%c;
        b=b>>1;
        a=(a*a)%c;
    }
    return temp; 
}
signed main()
{
    read(n);
    read(m);
    read(k);
    if(k>n) 
    {
        cout<<0;
        return 0;
    }
    for(re i=1;i<=m;++i)
    {
        read(val[i]);
    }
    ll temp1,temp2;
    for(re i=m;i>=1;--i)
    {
        temp1=1;
        temp2=1;
        for(re j=1;j<=k;++j)
        {
            temp1=(temp1*i)%mod;
            temp2=(temp2*(i-1))%mod;
        }
        ans+=(temp1-temp2)*val[i];
        ans=(ans+mod)%mod;
    }
    ll rate=1;
    for(re i=1;i<=k;++i)
    {
        rate=(rate*m)%mod;
    }
    ans=(ans*mont(rate,mod-2,mod)+mod)%mod;
    ans=(ans*(n-k+1)+mod)%mod;
    printf("%lld",ans);
}

















    
T3 code

 

T4 宝藏

考时操作

又是一道我没看出来的状压..

考后反思

看了一下午..对正解的理解全都在码里面了..

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define re register ll
const ll INF=0x3f3f3f3f;
ll n,m,ts;
ll from,to,value,ans;
ll f[1<<18][18];
ll dis[20][20];
ll g[1<<19];//可以直接连通的点及其本身.
//树的深度又叫做树的高度,即根固定,子节点到根节点的最远距离..
signed main()
{
    cin>>n;
    cin>>m;
    if(m==0)
    {
        cout<<0<<endl;
        return 0;
    }
    const ll alls=(1<<n)-1;
    memset(dis,0x3f,sizeof dis);
    memset(f,0x3f,sizeof f);
    for(re i=1;i<=m;++i)
    {
        cin>>from>>to>>value;
        dis[from][to]=min(dis[from][to],value);
        dis[to][from]=dis[from][to];
    }
    //预处理出各个状态直接连边可以达到的集合:
    for(re i=1;i<=alls;++i)
    {
        for(re j=1;j<=n;++j)
        {
            dis[j][j]=0;
            if((1<<(j-1)) & i) //j 属于 i
            {
                for(re k=1;k<=n;++k)
                {
                    if(dis[j][k]!=INF)
                    {
                        g[i]|=(1<<(k-1)); 
                        //预处理出对于每个点的集合所能拓展出的集合
                        //其实也可以不预处理..只不过可能会时间久一点..
                    }
                }
            }
            
        }
    }
    for(re i=0;i<=n-1;++i)
    {
        f[1<<i][0]=0;
    }
    //对于每个点,显然把 ta 作为通向地面的点的时候 ta 的深度为 0
    //更新值的大小:
    for(re i=1;i<=alls;++i)
    /*枚举集合,对于每个集合的子集,通过g[s]判断该子集是否 
     合法,如果合法,枚举所有需要被连向的点的最小边权求和 
     乘深度,作为答案*/ 
    {
        for(re s=i-1;s;s=((s-1)&i))
        //这个地方是在枚举i的所有非全集子集S作为前j - 1层的点,剩余点作为第j层的点
        //注意是所有非全集子集,而不是只少了一个元素的子集..这里要理解..可以画画图..
        //因为 i 可以通过很多种方式转移过来,所以位于第 j 层的点可以不止一个..
        {
            if((g[s] & i) == i)
            {
                ll sum=0;
                ll temp;
                ll ss=s xor i;
                //这里 ss 为 s 相对于 i 的补集..代表的是s可以直接连通且不包含其本身的集合..
                for(re j=1;j<=n;++j)
                {
                    if((1<<(j-1)) & ss)
                    //s直接连一条边就可以连到 i,这里的g[s]包括其本身..
                    {
                        temp=(ll)1e9;
                        for(re k=1;k<=n;++k)
                        //枚举最小边..触类旁通:由于这是一个图..所以成为i状态的方式有很多种..
                        {
                            if((1<<(k-1)) & s) 
                            {
                                temp=min(temp,dis[j][k]);
                            }
                        }
                        sum+=temp;
                    }
                }
                for(re j=1;j<=n;++j)
                { 
                  if(f[s][i-1]>=0)
                  {
                //     cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
                //     cout<<"f[s][j-1]:"<<f[s][j-1]<<" sum*j:"<<sum*j<<" ";
                //     cout<<"s:"<<s<<endl;
                     f[i][j]=min(f[i][j],f[s][j-1]+sum*j);
                //     cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
                  }
                }
            }
        }
    }
    ans=1e9;
    for(re i=1;i<=n;++i)//枚举树高..
    {
        ans=min(ans,f[alls][i]);
    }
    printf("%d",ans);
    return 0;
}
T4 code

 

posted @ 2021-06-14 10:51  AaMuXiiiiii  阅读(70)  评论(1)    收藏  举报