2016"百度之星" - 初赛(Astar Round2A)题解

来源:互联网 发布:淘宝9月份活动 编辑:程序博客网 时间:2024/05/22 11:04

今天是一年一度的百度之星初赛的日子啊,大家都早早的准备好了比(上)赛(分),运气也不错,涨了不少分,rating到了2222(真尼玛2)
ps.我是开黑做的,所以这分数不代表真实水平,勿黑

1001

给你一个由m个x组成的数字,模上k,问你是否等于c
k和c都小于10000,所以可以模拟,因为循环节不会大于10000,但是模拟很容易错,因为找到循环节的地方需要扣掉前面一段,然后各种XJB搞
模拟代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);//const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/int vis[10005];int main(){    int t,kase=0;    cin>>t;    while(t--){        int x;        LL m;        int k,c;        cin>>x>>m>>k>>c;        int mo=0;        mem(vis,0);        int xun=INF;        int tmp;        for(int i=1;i<=m;i++){            mo=(mo*10+x)%k;            if(vis[mo]){                xun=i-vis[mo];                tmp=vis[mo];                break;            }            vis[mo]=i;        }        kase++;        printf("Case #%d:\n",kase);        if(xun==INF){            if(mo!=c) printf("No\n");            else printf("Yes\n");        }        else{            m=(m-tmp)%xun;            int mm=mo;            for(int i=0;i<m;i++){                mm=(mm*10+x)%k;            }            if(mm!=c) printf("No\n");            else printf("Yes\n");        }    }    return 0;}

但是这题还有一种更加美妙的姿势,就是xxxx这样m个x,除以x之后就是m个1,乘9之后就是m个9,加1之后就是10m,所以我们可以求出10m19×x(modk),判断其是否等于c,但是这样做前面需要快速幂,然后模k了之后就不能直接除以9,所以我们可以这样算(10m1)×x(mod9k)9,这样就可以愉快的快速幂运算了。
ps.还有人说可以用矩阵快速幂搞,貌似也是可以的呢


1002

题意是给你n个数字,然后有些数字的位置已经固定,还有些数字的位置没有固定,让你给n个数字安排位置,使得相邻的数字的乘积和最大,有负数
首先需要记录,每个位置上是否有要求必须放第几个数
n最大范围是16,所以应该是状压,但是比赛时候我并不知道怎么dp,TAT
先确定状态dp[i][j],i为这会哪些数字已经被选(二进制表示),j为最后一个选的数字是哪一个,比如i的二进制表示里面有k个1,表示1-k的位置上都已经放了数字了,j就是第k个位置上面放的数是原来数组里面的哪一个
(这个状态挺巧妙的感觉,我承认我确实没有想到,状压dp还是太渣了)
这样的话状态转移就很简单了辣

dp[i|(1<<k))][k]=max(dp[i][j]+a[j]×a[k])

假设i的二进制表示里面有x个1,那么要保证第x个位置上必须要放k或者是没有要求,否则不能转移。
代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);//const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/LL dp[1<<18][20];int a[20];int b[20];int main(){    int t,kase=0;    cin>>t;    while(t--){        int n;        cin>>n;        mem(b,-1);        for(int i=0;i<(1<<n);i++){            for(int j=0;j<n;j++) dp[i][j]=-1e18;        }        for(int i=0;i<n;i++){            int p;            scanf("%d%d",&a[i],&p);            if(p!=-1) b[p]=i;        }        if(b[0]!=-1) dp[(1<<b[0])][b[0]]=0;        else for(int i=0;i<n;i++) dp[(1<<i)][i]=0;        for(int i=1;i<(1<<n);i++){            for(int j=0;j<n;j++){                if(i&(1<<j)){                    for(int k=0;k<n;k++){                        if((i&(1<<k))==0){                            int pos=bits(i);                            if(b[pos]==k||b[pos]==-1){                                dp[i|(1<<k)][k]=max(dp[i|(1<<k)][k],dp[i][j]+a[j]*a[k]);                            }                        }                    }                }            }        }        LL maxn=-1e18;        for(int i=0;i<n;i++){            maxn=max(maxn,dp[(1<<n)-1][i]);        }        kase++;        printf("Case #%d:\n",kase);        cout<<maxn<<endl;    }    return 0;}

1003

这是一道很不错的树上的题目,给你n个点的树,然后每个点有权值,有两种操作,一种是把某个点的权值修改,另一种是求一条从0开始必须经过x点的路径,使得路径上的点权和最大
因为要至少走到x,甚至要走到x的子树上,所以我们考虑可以用dfs序来解这题,因为dfs序的特性,我们维护每个点到0点的距离,这样就能很快用线段树求出在x的子树上的一点,它到0点的权值和最大
因为点权有负数,所以我们dfs的时候,dfs序只能在进入的时候++,出来的时候就不要++了,这样可以去掉很多0的节点(我的dfs序还是很弱啊,本来准备复习下,结果比赛就考了)
有了dfs序和线段树就很容易辣呀,这样就更新的时候区间加和ya[x],然后a[x]=y,然后维护区间内最大值,就好啦
代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);//const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/struct Edge{    int v,next;}edge[MAX*2];int head[MAX];int tot;int a[MAX];int ti;int p1[MAX];int p2[MAX];LL val[MAX];void init(){    mem(head,-1);    mem(val,0);    tot=0;    ti=0;}void add_edge(int a,int b){    edge[tot].v=b;    edge[tot].next=head[a];    head[a]=tot++;}LL sum[MAX<<2];LL col[MAX<<2];void pushup(int rt){    sum[rt]=max(sum[lrt],sum[rrt]);}void build(int l,int r,int rt){    col[rt]=0;    if(l==r){        sum[rt]=val[l];        return;    }    middle;    build(lson);    build(rson);    pushup(rt);}void pushdown(int rt,int m){    if(col[rt]){        col[lrt]+=col[rt];        col[rrt]+=col[rt];        sum[lrt]+=col[rt];        sum[rrt]+=col[rt];        col[rt]=0;    }}void update(int l,int r,int rt,int L,int R,LL d){    if(L<=l&&r<=R) {        col[rt]+=d;        sum[rt]+=d;        return ;    }    middle;    if(col[rt]!=0) pushdown(rt,r-l+1);    if(L<=m) update(lson,L,R,d);    if(R>m) update(rson,L,R,d);    pushup(rt);}LL query(int l,int r,int rt,int L,int R){    if(L<=l&&r<=R) return sum[rt];    if(col[rt]) pushdown(rt,r-l+1);    middle;    LL ret=-1e18;    if(L<=m) ret=max(query(lson,L,R),ret);    if(R>m) ret=max(ret,query(rson,L,R));    return ret;}void dfs(int u,int fa,LL c){    p1[u]=++ti;    val[ti]=c;    for(int i=head[u];i!=-1;i=edge[i].next){        int v=edge[i].v;        if(v==fa) continue;        dfs(v,u,c+a[v]);    }    p2[u]=ti;}int main(){    int t,kase=0;    cin>>t;    while(t--){        int n,m;        cin>>n>>m;        init();        for(int i=1;i<n;i++){            int x,y;            scanf("%d%d",&x,&y);            add_edge(x,y);            add_edge(y,x);        }        for(int i=0;i<n;i++) scanf("%d",&a[i]);        kase++;        printf("Case #%d:\n",kase);        dfs(0,-1,a[0]);        build(1,ti,1);        while(m--){            int op,x;            LL y;            scanf("%d%d",&op,&x);            if(op==0){                scanf("%I64d",&y);                update(1,ti,1,p1[x],p2[x],y-a[x]);                a[x]=y;            }            else printf("%I64d\n",query(1,ti,1,p1[x],p2[x]));        }    }    return 0;}

1004

额。。。不会


1005

给你一个字符串的定义,就是里面有B也有D,然后有filp操作,就是把B变成D,D变成B,然后还有反向操作,就是把字符串倒置
然后问你在区间[L,R]之间有多少个B
第一反应这题肯定是求solve(R)solve(L1)
然后就是怎么求1-x之间有多少个B的问题了,我们先打表找出,每个字符串k,它的长度len和里面含有的B的个数f,

f(i)=f(i1)+1+(len(i1)f(i1))=len(i1)+1

然后对于字符串1-x,我们可以找到一条最长的,但是长度小于等于R的,完整的串k,如果长度正好为x,就可以returnf(k)
否则就是考虑k串后面还多几个,后面是还多xlen(k)1个,但是考虑到这些里面的B,不就是前面完整的串结尾的D的个数么,所以我们可以把这两段里面的B放一起计算,加上中间添的一个B,就是最后长度2×x2×len(k)1里面有xlen(k)个B,然后可以递归求解前面长度为2×len(k)+1x的串里面有多少个B
代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define   MAX           205#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/LL f[70];LL len[70];void init(){    len[1]=1;    f[1]=1;    for(int i=2;;i++){        len[i]=len[i-1]*2+1;        f[i]=len[i-1]+1;        if(len[i]>=1e18) break;    }}LL solve(LL x){    if(x==0) return 0;    int k=1;    for(;;k++){        if(len[k]>x) break;    }    k--;    if(len[k]==x){        return f[k];    }    else return solve(2*len[k]-x+1)+x-len[k];}int main(){    //freopen("in.txt","r",stdin);    int t;    cin>>t;    init();    while(t--){        LL l,r;        scanf("%I64d%I64d",&l,&r);        printf("%I64d\n",solve(r)-solve(l-1));    }    return 0;}

1006

给你n个人的编号,编号就是他的值,然后排队,每次放进去一个人的时候可以加上一个值,这个值是他和他前面的所有人里面的最小值,但是有一些限制,就是有的人必须在有的人后面。求最后得到的和的最大值
首先我们考虑和要最大,那必须是大的人先放,再放小的,但是又有限制,就好比点的入度,就是一个点必须在另外个点的前面,拓扑序,所以我们可以模拟拓扑排序,把没有限制的点放进优先队列里,然后往外面取,每次取一个就接触它对别的点的限制,然后记录一个从第一个点到它的最小值就可以了
代码:

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);//const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/vector<int> v[MAX];int deg[MAX];int main(){    int t,kase=0;    cin>>t;    while(t--){        int n,m;        cin>>n>>m;        for(int i=1;i<=n;i++) v[i].clear();        mem(deg,0);        for(int i=0;i<m;i++){            int a,b;            scanf("%d%d",&a,&b);            v[a].push_back(b);            deg[b]++;        }        priority_queue<int> q;        for(int i=1;i<=n;i++){            if(deg[i]==0) q.push(i);        }        int mini=INF;        LL ans=0;        while(!q.empty()){            int x=q.top();q.pop();            mini=min(mini,x);            ans+=mini;            for(int i=0;i<v[x].size();i++){                deg[v[x][i]]--;                if(deg[v[x][i]]==0) q.push(v[x][i]);            }        }        cout<<ans<<endl;    }    return 0;}
0 0
原创粉丝点击