NOI2015 Day1

不知不觉省选完已经颓了半个月了!!!还两个月就要 NOI 了。。很慌。。
前几天做 NOI2016 翻车以后。。今天开始先做 2015Day1
第一题:
这么裸这么和善的并查集么。。(我才不会告诉你先做的时候看错了题结果竟然还有80。。数据不要这么水吧。。)

第二题:
这么 SB 的树剖吗!? Install 就查询该点到根路径上0的个数,然后全部赋为1, Uninstall 就查询以该点为跟的子树1的个数,然后赋为0。。

第三题:
这个题看起来好像也可做啊。。然而我最终还是只打了表。。还只有20分。
看看题解。哇,状压dp。
发现取一个数相当于取到它所有的质因数。然后大于根号500的质因数每个数最多只有一个(废话),小于根号500的质因数只有8个,8个!然后就可以状压了。
然后就是处理大于根号500的质因数的问题。我们可以将所有数按最大质因数(大于根号500的)排序。然后相邻相等的不重复处理就好辣!
f[i][j] 表示第一个人状态为 i ,第二个人为j的方案数。
g[0/1][i][j] 表示当前数放到第1/2个人后,第一个人状态为 i ,第二个人为j的方案数。
然后 f[i][j]=g[0][i][j]+g[1][i][j]f[i][j]) 为什么要减呢?
因为都不取的算了两次呀~

T1

#include <cstdio>
#include <iostream>
#include <algorithm>
#define N  100005
using namespace std;

int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,T,tot;
int father[N<<1],hash[N<<1];

class Operation{
    public:
        int x,y;bool z;
}e[N];

bool operator <(Operation a,Operation b){
    return a.z>b.z;
}

int Find(int x)
{
    int l=1,r=tot,rtn;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(hash[mid]>=x) rtn=mid,r=mid-1;
        else l=mid+1;
    }
    return rtn;
}

int Findf(int x){
    return father[x]==x?x:father[x]=Findf(father[x]);
}

void Input_Init()
{
    n=read();tot=0;
    for(int i=1;i<=n;i++)
    {
        hash[++tot]=e[i].x=read();
        hash[++tot]=e[i].y=read();
        e[i].z=read();
    }
    sort(hash+1,hash+1+tot);
    tot=unique(hash+1,hash+1+tot)-hash-1;
    for(int i=1;i<=tot;i++) father[i]=i;
}

bool Solve()
{
    sort(e+1,e+1+n);
    for(int i=1;i<=n;i++)
    {
        e[i].x=Find(e[i].x);
        e[i].y=Find(e[i].y);
        int fx=Findf(e[i].x),fy=Findf(e[i].y);
        if(!e[i].z)
        {
            if(fx==fy) 
                return false;
        }   
        else
            father[fx]=fy;
    }
    return true;
}

int main()
{
    T=read();
    while(T--)
    {
        Input_Init();
        if(Solve()) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

T2

#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 100005
using namespace std;

int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,cnt,m,ind;
int b[N],p[N],nextedge[N];
int son[N],fa[N],top[N],pos[N],Fpos[N],sz[N],deep[N];

class Seg_Tree{
    public:
    int l,r,sum,tag;
}e[N<<2];

void Add(int x,int y)
{
    cnt++;
    b[cnt]=y;
    nextedge[cnt]=p[x];
    p[x]=cnt;
}

void Dfs(int x)
{
    sz[x]=1;
    for(int i=p[x];i;i=nextedge[i])
    {
        int v=b[i];
        deep[v]=deep[x]+1;
        Dfs(v);sz[x]+=sz[v];
        son[x]=sz[son[x]]<sz[v]?v:son[x];
    }
}

void dfs(int x,int root)
{
    pos[x]=++ind;top[x]=root;Fpos[pos[x]]=x;
    if(!son[x]) return;
    dfs(son[x],root);
    for(int i=p[x];i;i=nextedge[i])
    {
        int v=b[i];
        if(v==son[x]) continue;
        dfs(v,v);
    }
}

void Build(int p,int l,int r)
{
    e[p].l=l,e[p].r=r,e[p].tag=-1;
    if(l==r) return;
    int mid=l+r>>1;
    Build(p<<1,l,mid);Build(p<<1|1,mid+1,r);
}

int Len(Seg_Tree a){
    return a.r-a.l+1;
}

void pushdown(int p)
{
    e[p<<1].sum=e[p].tag*Len(e[p<<1]);
    e[p<<1|1].sum=e[p].tag*Len(e[p<<1|1]);
    e[p<<1].tag=e[p].tag;e[p<<1|1].tag=e[p].tag;
    e[p].tag=-1;
}

void pushup(int p){
    e[p].sum=e[p<<1].sum+e[p<<1|1].sum;
}

int Query(int p,int x,int y)
{
    int l=e[p].l,r=e[p].r,mid=l+r>>1;
    if(l==x&&y==r)
        return e[p].sum;
    if(e[p].tag!=-1) pushdown(p);
    if(y<=mid) return Query(p<<1,x,y);
    if(x>mid) return Query(p<<1|1,x,y);
    return Query(p<<1,x,mid)+Query(p<<1|1,mid+1,y);
}

void Update(int p,int x,int y,int z)
{
    int l=e[p].l,r=e[p].r,mid=l+r>>1;
    if(l==x&&y==r)
    {
        e[p].sum=Len(e[p])*z;
        e[p].tag=z;return;
    }
    if(y<=mid) Update(p<<1,x,y,z);
    else if(x>mid) Update(p<<1|1,x,y,z);
    else Update(p<<1,x,mid,z),Update(p<<1|1,mid+1,y,z);
    pushup(p);
}

void Install(int x)
{
    int fx=top[x],ans=deep[x]+1;
    while(fx!=1)
    {
        ans-=Query(1,pos[fx],pos[x]);
        Update(1,pos[fx],pos[x],1);
        x=fa[fx],fx=top[x];
    }
    ans-=Query(1,1,pos[x]);
    Update(1,1,pos[x],1);
    printf("%d\n",ans);
}

void Uninstall(int x)
{
    printf("%d\n",Query(1,pos[x],pos[x]+sz[x]-1));
    Update(1,pos[x],pos[x]+sz[x]-1,0);
}

int main()
{
    //freopen("D:\\oi\\in.txt","r",stdin);
    n=read();
    for(int i=2;i<=n;i++) Add(fa[i]=read()+1,i);
    Dfs(1);dfs(1,1);Build(1,1,n);
    m=read();
    for(int i=1;i<=m;i++)
    {
        char ch[10];static int x;
        scanf("%s",ch);x=read()+1;
        if(ch[0]=='i') Install(x);
        else Uninstall(x);
    }
    return 0;
}

T3

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define N 100005
const int Lim=255;
using namespace std;
typedef long long ll;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,mod;
ll ans; 
int p[]={2,3,5,7,11,13,17,19};
ll f[260][260],g[2][260][260];

class Digit{
    public:
        int S,Big;
}e[501];

bool operator <(Digit a,Digit b){
    return a.Big<b.Big;
}

int main()
{
    n=read(),mod=read();
    for(int i=2,x;i<=n;i++)
    {
        x=i;
        for(int j=0;j<8;j++)
        {
            if(i%p[j]>0) continue;
            e[i].S|=(1<<j);
            while(x%p[j]==0) x/=p[j];
        }
        e[i].Big=x;
    }
    sort(e+2,e+1+n);f[0][0]=1;
    for(int i=2;i<=n;i++)
    {
        if(i==2||e[i].Big!=e[i-1].Big||e[i].Big==1)
        {
            memcpy(g[0],f,sizeof(g[0]));
            memcpy(g[1],f,sizeof(g[1]));
        }
        for(int j=Lim;~j;j--)
        {
            for(int k=Lim;~k;k--)
            {
                if((j&k)>0) continue;
                if((e[i].S&k)==0) 
                    g[0][j|e[i].S][k]+=g[0][j][k],g[0][j|e[i].S][k]%=mod;
                if((e[i].S&j)==0)
                    g[1][j][k|e[i].S]+=g[1][j][k],g[1][j][k|e[i].S]%=mod;
            }
        }
        if(i==n||e[i].Big==1||e[i].Big!=e[i+1].Big)
        {
            for(int j=Lim;~j;j--)
                for(int k=Lim;~k;k--)
                {
                    if((j&k)>0) continue;
                    f[j][k]=(g[0][j][k]+g[1][j][k]-f[j][k]);
                }
        }
    }
    for(int i=0;i<=Lim;i++)
    for(int j=0;j<=Lim;j++)
        if((i&j)==0)
            ans=(ans+f[i][j])%mod;
    ans=(ans+mod)%mod;
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值