2017.10.15离线赛总结

prime ——3784

思路:筛一筛质数,再将质数的倍数判一下,前缀和维护,然而这样就卡过去了…当然,正解无非就是更强大的筛法——线性筛。然而,老司机(小c)还有一种做法:将一个数除以其最大质因子,再判断商的最大质因子是否为本身这样似乎不用线性筛就更快了…那么我就将二者结合一下。

#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define LL long long
#define N 10000005
using namespace std;
int Q,L,R;
int sum[N];
int mark[N],p[N],cnt;
void Init(){
    mark[1]=1;
    REP(i,2,N){
        if(!mark[i])p[cnt++]=mark[i]=i;
        REP(j,0,cnt){
            LL x=1ll*p[j]*i;
            if(x>=N)break;
            mark[x]=p[j];
            if(!(i%p[j]))break;
        }
    }
    REP(i,2,N){
        int x=i/mark[i];
        sum[i]=sum[i-1]+(mark[x]==x);
    }
} 
int main(){
//  freopen("prime.in","r",stdin);
//  freopen("prime.out","w",stdout);
    Init();
    scanf("%d",&Q);
    while(Q--){
        scanf("%d%d",&L,&R);
        printf("%d\n",sum[R]-sum[L-1]);
    }
    return 0;
} 

room ——3785

思路:bfs,不解释了,太明显了…But今天一开始切分(求稳),结果切着切着分就少了(tm着样例太水了)…However,这里要状压,常数有点大吧

#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define LL long long
#define INF 0x3f3f3f3f
#define N 10005
#define M 10005
#define K 15
using namespace std;
int n,m,k;

struct P30{
    int d[105][505];
    void solve(){
        memset(d,INF,sizeof(d));
        REP(i,1,m){
            int a,b;
            scanf("%d%d",&a,&b);
            d[a][b]=1;
        }
        d[1][1]=0;
        REP(l,1,n){ 
            REP(i,1,n){
                if(i==k)continue;
                REP(j,1,n){
                    if(i==j || j==k)continue;
                    d[i][j]=min(d[i][j],d[i][l]+d[l][j]);
                }
            }
        }
        if(d[1][n]==INF)puts("No Solution");
        else printf("%d\n",d[1][n]);
    }
}p30;
struct P50{
    int d[N];
    struct node{
        int from,to;
    }es[M];
    void Bellman(){
        memset(d,INF,sizeof(d));
        d[1]=0;
        while(1){
            bool f=0;
            REP(i,1,m)if(d[es[i].from]!=INF && d[es[i].to]>d[es[i].from]+1)f=1,d[es[i].to]=d[es[i].from]+1;
            if(!f)break;
        }
    }
    void solve(){
        REP(i,1,m)scanf("%d%d",&es[i].from,&es[i].to);
        Bellman();
        if(d[n]==INF)puts("No Solution");
        else printf("%d\n",d[n]);
    }
}p50;
struct P100{
    int get[N],vis[N][1<<11];
    struct edge{
        int to,mark;
    };
    vector<edge>E[M];
    struct node{
        int step,x,used;
    };
    queue<node>Q;
    void bfs(){
        Q.push((node){0,1,get[1]});

        while(!Q.empty()){
            node now=Q.front();Q.pop();
            if(now.x==n){
                printf("%d\n",now.step);
                exit(0);
            }   
            REP(i,0,E[now.x].size()-1){
                edge y=E[now.x][i];
                if((now.used|y.mark)!=now.used)continue;
                node nxt;
                nxt.x=y.to;
                nxt.step=now.step+1;
                nxt.used=now.used|get[y.to];
                if(vis[nxt.x][nxt.used])continue;
                vis[nxt.x][nxt.used]=nxt.step;
                Q.push(nxt);
            }
        }
    }
    void solve(){
        REP(i,1,n){
            int f;
            get[i]=0;
            REP(j,0,k-1){
                scanf("%d",&f);
                if(f)get[i]|=1<<j;
            }
        }
        REP(i,1,m){
            int a,b,f;
            scanf("%d%d",&a,&b);
            edge tmp;
            tmp.to=b;
            tmp.mark=0;
            REP(j,0,k-1){
                scanf("%d",&f);
                if(f)tmp.mark|=1<<j;
            }
            E[a].push_back(tmp);
        }
        bfs();
        puts("No Solution");
    }
}p100;
int main(){
//  freopen("room.in","r",stdin);
//  freopen("room.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    if(!k && n<=100)p30.solve();
    else if(!k && n<=1000)p50.solve();
    else p100.solve();
    return 0;
}

light ——3786

思路:题意简单明了,就是求树上的两条路径的的重复的点,而且这里两点路径分别为a->b,c->b,那就更显然了,求出两两之间的lca分类讨论一下就出来了,这里分类讨论也是出奇的少,总而言之判一下路径是否覆盖——即a与b的lca和b与c的lca相等时,反之…

#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define INF 0x3f3f3f3f
#define N 200005
#define S 20
using namespace std;
int n,Q,num;

vector<int>E[N];
int D[N],fa[S][N];

struct PList{
    int Dx;
    void dfs(int x,int f){
        D[x]=D[f]+1;
        REP(i,0,E[x].size()-1){
            int y=E[x][i];
            if(y==f)continue;
            dfs(y,x);
        }
    }
    void solve(){
        REP(i,1,n)if(E[i].size()<2)Dx=i;
        dfs(Dx,0);
        REP(i,1,Q){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(D[a]>=D[b] && D[c]>=D[b])printf("%d\n",min(D[a],D[c])-D[b]+1);
            else if(D[a]<=D[b] && D[c]<=D[b])printf("%d\n",D[b]-max(D[a],D[c])+1);
            else puts("1");
        }
    }
}p_list;
struct P100{
    void Up(int &x,int step){
        DREP(i,S-1,0)if(step&(1<<i))x=fa[i][x];
    } 
    int Lca(int a,int b){
        if(D[a]>D[b])swap(a,b);
        Up(b,D[b]-D[a]);
        if(a==b)return a;
        DREP(i,S-1,0)if(fa[i][a]!=fa[i][b])a=fa[i][a],b=fa[i][b];
        return fa[0][a];
    }
    void Init(){
        REP(j,1,S-1)
                REP(i,1,n)
                    fa[j][i]=fa[j-1][fa[j-1][i]];
    }
    void dfs(int x,int f){
        D[x]=D[f]+1;
        fa[0][x]=f;
        REP(i,0,E[x].size()-1){
            int y=E[x][i];
            if(y==f)continue;
            dfs(y,x);
        } 
    }
    void solve(){
        dfs(1,0); 
        Init();
        REP(i,1,Q){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            int lca1=Lca(a,b),lca2=Lca(b,c),lca3=Lca(a,c);
            printf("%d\n",lca1==lca2?D[lca3]-2*D[lca1]+D[b]+1:D[b]-max(D[lca1],D[lca2])+1);
        }
    }
}p100;
int main(){
//  freopen("light.in","r",stdin);
//  freopen("light.out","w",stdout);
    scanf("%d%d%d",&n,&Q,&num);
    REP(i,1,n-1){
        int a,b;
        scanf("%d%d",&a,&b);
        E[a].push_back(b);
        E[b].push_back(a);
    }
    if(num>=11 && num<=13 || num>=17 && num<=18)p_list.solve();
    else p100.solve(); 
    return 0;
}

小结:今天的题比较水,但是该ak的还是没有,切分还是不熟练吧(暴力敲太快了,cost打成to…)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值