训练11

4012: What is the Rank?

题意:给定n个数,按顺序将数添加进集合中,并输出该数在当前集合中是第几大

#include<bits/stdc++.h>
using namespace std;
const int Max=45005;
struct node
{
     int x,y;
}e[Max];
int cmp(node a,node b)
{
    return a.y>b.y;
}
int cmp1(node a,node b)
{
    return a.x<b.x;
}
int f[Max];
void update(int x)
{
    for(int i=x;i<Max;i+=i&-i)
    {
        f[i]+=1;
    }
}
int query(int x)
{
    int sum=0;
    for(int i=x;i>0;i-=i&-i)
    {
        sum+=f[i];
    }
    return sum;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&e[i].y);
        e[i].x=i;
    }
    sort(e+1,e+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        e[i].y=i;
    }
    sort(e+1,e+n+1,cmp1);
    for(int i=1;i<=n;i++)
    {
        update(e[i].y);
        printf("%d\n",query(e[i].y));
    }
}

//hash+树状数组

3656: Intersections

题意:给定一个圆和一条线段,求圆与线段是否相交

思路:1.线段两点均在圆内则不相交;

2.线段两点有一点在圆内,另一点在圆外则相交(有点在圆上为相交);

3.当两点均在圆外时,先求圆心在直线上的垂足,垂足在圆外则不相交,若垂足在圆内(包括圆上),继续判断线段两点是否相对垂足在同方向,同向为不相交,反向相交;

对点(x1,y1),(x2,y2)求出一般式:AX+BY+C=0

A=y2-y1    B=x1-x2     C=x2*y1-x1*y2

根据 A B C以及圆心(x,y)求出垂足(x3,y3)

x3=(b*b*x-a*b*y-a*c)/(a*a+b*b);y3=(a*a*y-a*b*x-b*c)/(a*a+b*b);

#include<bits/stdc++.h>
using namespace std;
void printY()
{
   printf("The line segment intersects the circle.\n");
}
void printN()
{
    printf("The line segment does not intersect the circle.\n");
}
int main()
{
    double x,y,r,x1,y1,x2,y2;
    while(~scanf("%lf%lf%lf",&x,&y,&r))
     {
         scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
         double a=y2-y1;
         double b=x1-x2;
         double c=x2*y1-x1*y2;
         double x3=(b*b*x-a*b*y-a*c)/(a*a+b*b);
         double y3=(a*a*y-a*b*x-b*c)/(a*a+b*b);
         if((x-x1)*(x-x1)+(y-y1)*(y-y1)<r*r)
         {
             if((x-x2)*(x-x2)+(y-y2)*(y-y2)<r*r)
             printN();
             else
             printY();
         }
         else
         {
             if((x-x2)*(x-x2)+(y-y2)*(y-y2)<r*r)
               printY();
             else
             {
                 if((x-x3)*(x-x3)+(y-y3)*(y-y3)<=r*r)
                 {
                     if(x3==x2)
                     {
                         if((y3-y2)/abs(y3-y2)==(y3-y1)/abs(y3-y1))
                          printN();
                         else
                          printY();
                     }
                     else
                     {
                         if((x3-x2)/abs(x3-x2)==(x3-x1)/abs(x3-x1))
                          printN();
                         else
                          printY();
                     }
                 }
                 else
                 {
                     printN();
                 }
             }
         }
     }
}

//数学 

4613: Number of Battlefields

题意:给定一个周长p,问有多少形状的周长为p(不能为矩形)

矩阵快速幂求斐波那契数列

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=987654321;
void mul(ll b[2][2],ll a[2][2])
{
    ll c[2][2]={0};
    for(int i=0;i<=1;i++)
    {
        for(int j=0;j<=1;j++)
        {
            c[i][j]=b[i][0]*a[0][j]%MOD+b[i][1]*a[1][j]%MOD;
        }
    }
    memcpy(b,c,sizeof(c));
}
void power(ll a[2][2],int p)
{
    ll b[2][2]={1,0,1,0};
    while(p)
    {
        if(p&1)
        {
            mul(b,a);
        }
        mul(a,a);
        p/=2;
    }
    memcpy(a,b,sizeof(b));
}
int main()
{
    int p;
    while(scanf("%d",&p),p)
    {
        if (p&1||p<8)
        {
            printf("0\n");
            continue;
        }
        p=(p-4)/2;
        ll a[2][2]={1,1,1,0};
        power(a,2*p);
        printf("%lld\n",(a[1][0]-p-1+MOD)%MOD);
    }
}

4505: KOSARE

题意:有n个盒子,m种类的玩具。n个盒子各自装有一定不同种类的玩具,现在请你选择一些盒子,使得这些盒子的玩具包含全部种类;问有多少种选择能够满足条件

#include<bits/stdc++.h>
using namespace std;
const int Max=(1<<20)+5;
const int Mod=1000000007;
int cnt[Max],num[Max],ans[Max];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    cnt[0]=1;
    int f=1<<m;
    for(int i=1;i<=n;i++)
    {
        cnt[i]=(cnt[i-1]*2)%Mod;
        int k,s=0;
        scanf("%d",&k);
        for(int j=1;j<=k;j++)
        {
            int x;
            scanf("%d",&x);
            s+=1<<x-1;
        }
        num[s]++;
    }
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<f;j++)
        {
            if(j&(1<<i))num[j]+=num[j-(1<<i)];
        }
    }
    for(int i=0;i<f;i++)
    {
        ans[i]=cnt[num[i]];
    }
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<f;j++)
        {
            if(j&(1<<i))ans[j]=(ans[j]-ans[j-(1<<i)]+Mod)%Mod;
        }
    }
    printf("%d\n",ans[f-1]%Mod);
}

//容斥原理+状压DP

6043: Tunnel Warfare

题意:一条直线上有n个村庄,目前有三种操作,D操作,将该村庄破坏,Q操作,查询有该村庄直接连接或间接连接的村庄数(包括自身),R操作将最近被破坏的村庄重建;

#include<bits/stdc++.h>
using namespace std;
const int Max=50005;
struct node{
   int llen,rlen,mlen;
}e[Max*4];
void Build(int l,int r,int i)
{
    e[i].llen=e[i].rlen=e[i].mlen=r-l+1;
    int mid=(l+r)/2;
    if(l==r)return ;
    Build(l,mid,i*2);
    Build(mid+1,r,i*2+1);
}
void Update(int l,int r,int i,int nod,int flag)
{
    if(l==r)
    {
        e[i].llen=e[i].rlen=e[i].mlen=flag;
        return ;
    }
    int mid=(l+r)/2;
    if(nod<=mid)Update(l,mid,i*2,nod,flag);
    else Update(mid+1,r,i*2+1,nod,flag);
    e[i].llen=e[2*i].llen;
    e[i].rlen=e[2*i+1].rlen;
    e[i].mlen=max(max(e[i*2].mlen,e[i*2+1].mlen),e[i*2].rlen+e[i*2+1].llen);
    if(e[2*i].llen==mid-l+1)
        e[i].llen+=e[2*i+1].llen;
    if(e[i*2+1].rlen==r-mid)
        e[i].rlen+=e[2*i].rlen;
}
int Query(int l,int r,int i,int x)
{
    if(l==r||e[i].mlen==0||e[i].mlen==r-l+1)
    {
        return e[i].mlen;
    }
    int mid=(l+r)/2;
    if(x<=mid)
    {
        if(x>=mid-e[i*2].rlen+1)
            return Query(l,mid,i*2,x)+Query(mid+1,r,i*2+1,mid+1);
         else
            return Query(l,mid,i*2,x);
    }
    else
    {
        if(x<=mid+1+e[i*2+1].llen-1)
            return Query(mid+1,r,i*2+1,x)+Query(l,mid,i*2,mid);
        else
            return Query(mid+1,r,i*2+1,x);
    }
}
stack<int> st;
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    Build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        getchar();
        char ch;
        scanf("%c",&ch);
        if(ch=='D')
        {
            int x;
            scanf("%d",&x);
            Update(1,n,1,x,0);
            st.push(x);
        }
        else if(ch=='Q')
        {   int x;
            scanf("%d",&x);
            printf("%d\n",Query(1,n,1,x));
        }
        else
        {
            if(!st.size())continue;
            int x=st.top();
            st.pop();
            Update(1,n,1,x,1);
        }
    }
}

6073: Visible Trees

题意:可将题目理解为区间[1,n]与区间[1,m]有多少对数互质

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Max=100005;
int prim[Max],num[Max][20];
void init()
{
    for(int i=2;i<Max;i++)
    {
        if(prim[i]==0)
        {
            num[i][0]++;//num[i][0]记录i可分解质因子的个数
            num[i][1]=i;
            for(int j=2*i;j<Max;j+=i)
            {
                prim[j]=1;
                num[j][++num[j][0]]=i;//添加j的质因子
            }
        }
    }
}
ll dfs(int id,int idm,int n)//返回不大于n的书中与idm不互质的数的个数;
{
    ll sum=0;
    for(int j=id;j<=num[idm][0];j++)
    {
        sum+=n/num[idm][j]-dfs(j+1,idm,n/num[idm][j]);
    }
    return sum;
}
int main()
{
    int t;
    scanf("%d",&t);
    init();
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        ll sum=0;
        for(int i=2;i<=m;i++)
        {
            sum+=n-dfs(1,i,n);
        }
        printf("%lld\n",sum+n);
    }
}

//容斥原理

6086: Railway

题意:给定一个无向图,如果一条边处在多个环中,就是一条冲突边,如果不在环中,就不是无用边,求有多少无用边以及多少冲突边

#include<bits/stdc++.h>
using namespace std;
const int Max=10005;
int low[Max],dfn[Max],index,ans,ans1;
vector<int> G[Max];
struct Edge{
   int from,to;
}tmp;
stack<Edge> st;
set<int> s;
void init()
{
    memset(low,0,sizeof(low));
    memset(dfn,-1,sizeof(dfn));
    for(int i=0;i<Max;i++)
        G[i].clear();
        index=0;
        ans=0;
        ans1=0;
}
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++index;//图中第index个第一次被遍历的点
    for(int i=0;i<G[u].size();i++)//遍历连接点
    {
        int v=G[u][i];
        if(dfn[v]==-1)//节点v未曾遍历过
        {
            tmp.from=u,tmp.to=v;
            st.push(tmp);
            tarjan(v,u);
            low[u]=min(low[u],low[v]);//更新u节点的low值
            if(low[v]>=dfn[u])//子节点v不能回连至u节点之前的节点
            {
                s.clear();
                int cnt=0;//边数
                do{
                    cnt++;
                     tmp=st.top();
                    st.pop();
                    s.insert(tmp.from);
                    s.insert(tmp.to);
                }while(tmp.from!=u||tmp.to!=v);
                if(cnt>s.size())ans1+=cnt;
                if(low[v]>dfn[u])//v节点的后代不能回连到u之前的节点,桥加1
                    ans++;
            }
        }
        else if(v!=fa&&dfn[v]<dfn[u])//v不为u的父节点
        {
            tmp.from=u,tmp.to=v;
            st.push(tmp);
            if(low[u]>dfn[v])low[u]=dfn[v];//更新u节点的low值
        }
    }
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m),n||m)
    {
          init();
          for(int i=1;i<=m;i++)
          {
              int x,y;
              scanf("%d%d",&x,&y);
              G[x].push_back(y);
              G[y].push_back(x);
          }
          for(int i=0;i<n;i++)
          {
              if(dfn[i]==-1)
              tarjan(0,-1);
          }
          printf("%d %d\n",ans,ans1);
    }
}

6098: Portal

题意:a,b两点之间有多条路径,每条路径可能是由多条边组成,这条路径的值就是最长边的值,在给完所有的边信息后,有q次询问,花费在L以内的路径有多少条;

#include<bits/stdc++.h>
using namespace std;
struct edge{
    int u,v,cost;
}e[50005];
struct node{
    int id,l;
}s[10005];
int n,m,q,f[10005],r[10005],ans[10005];
void init()
{
    for(int i=0;i<=n;i++)
    {
        f[i]=i;
        r[i]=1;
    }
    memset(ans,0,sizeof(ans));
}
int cmp(edge a,edge b)
{
    return a.cost<b.cost;
}
int cmp1(node a,node b)
{
    return a.l<b.l;
}
int find(int x)
{
    return f[x]==x?x:f[x]=find(f[x]);
}
void Union(int a, int b)
{
    if(r[a]>=r[b])
    {
        f[b]=a;
        r[a]+=r[b];
    }
    else
    {
        f[a]=b;
        r[b]+=r[a];
    }
}
int main()
{

    while(~scanf("%d%d%d",&n,&m,&q))
    {
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].cost);
        }
        for(int i=1;i<=q;i++)
        {
            scanf("%d",&s[i].l);
            s[i].id=i;
        }
        sort(e+1,e+m+1,cmp);
        sort(s+1,s+q+1,cmp1);
        int t=1;
        for(int i=1;i<=q;i++)
        {
            if(i>1)ans[s[i].id]=ans[s[i-1].id];
            while(e[t].cost<=s[i].l&&t<=m)
            {
                int t1=find(e[t].u);
                int t2=find(e[t].v);
                if(t1!=t2)
                {
                    ans[s[i].id]+=r[t1]*r[t2];
                    Union(t1,t2);
                }
                t++;
            }
        }
        for(int i=1;i<=q;i++)
            printf("%d\n",ans[i]);
    }
}

//离线+并查集

 

 

 

 

posted on 2019-11-15 13:09  还是力量不够  阅读(151)  评论(0)    收藏  举报

导航