AmazingCounters.com

2017-4-13校内训练

坑题+SB数据结构训练赛

 

A.题目大意:某个地方有五个城市,给出十条单向边的长度,分别为1~2,1~3,2~3,2~4,3~4,3~5,4~5,4~1,5~1,5~2,问从一号城开始走,走长度恰好为n,走的城市数最少且字典序最小的方案。(1<=边长<=n<=500,000)

思路:以在第i个城市走了长度为j为状态做bfs,字典序小的先拓展,复杂度O(15n)。

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
    return x;
}
#define MN 500000
int d[5][2],u[5][MN+5],rx[5][MN+5],ry[5][MN+5],qx[5*MN+5],qy[5*MN+5],qn;
void out(int x,int y)
{
    if(y)out(rx[x][y],ry[x][y]);
    printf("%d ",x+1);
}
int main()
{
    int n=read(),i,x,y,xx,yy,a,b;
    for(i=0;i<5;++i)d[i][0]=read(),d[i][1]=read();
    for(i=0;i<=qn;++i)
    {
        x=qx[i];y=qy[i];
        if(y==n){out(x,y);return 0;}
        a=1;b=2;if((x+a)%5>(x+b)%5)swap(a,b);
        xx=(x+a)%5;yy=y+d[x][a-1];
        if(yy<=n&&!u[xx][yy])++qn,u[qx[qn]=xx][qy[qn]=yy]=1,rx[xx][yy]=x,ry[xx][yy]=y;
        xx=(x+b)%5;yy=y+d[x][b-1];
        if(yy<=n&&!u[xx][yy])++qn,u[qx[qn]=xx][qy[qn]=yy]=1,rx[xx][yy]=x,ry[xx][yy]=y;
    }
    puts("-1");
}

 

B.题目大意:给出一个长度为n的序列,问有多少子串的乘积为完全平方数。(n<=500,000,数字大小<=10^6)

思路:分解质因数后各质因子个数均为偶数即为完全平方数,那么同种质因子每有一个就异或上一个1,各种质因子异或出的数都为0即为完全平方数,按这个思路求一个前缀异或和,两个相同的前缀异或和即对应一个乘积为完全平方数的子串,hash一下上map就没了,复杂度O(nlogn)。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
    return x;
}
#define MX 1000000
map<ll,int> mp[3];
const int magic[3]={31,37,233};
ll f[3][MX+5],ff[3];
int u[MX+5],uu[MX+5],p[MX+5],pn;
void push(int x)
{
    if(uu[x]^=1)for(int i=0;i<3;++i)ff[i]+=f[i][x];
    else for(int i=0;i<3;++i)ff[i]-=f[i][x];
}
int main()
{
    int n=read(),i,j;ll ans=0;
    for(i=2;i<=MX;++i)
    {
        if(!u[i])p[++pn]=i,u[i]=i;
        for(j=1;i*p[j]<=MX;++j){u[i*p[j]]=p[j];if(i%p[j]==0)break;}
    }
    for(i=0;i<3;++i)for(f[i][0]=j=1;j<=MX;++j)f[i][j]=f[i][j-1]*magic[i];
    for(i=0;i<3;++i)++mp[i][0];
    while(n--)
    {
        for(i=read();i>1;i/=u[i])push(u[i]);
        for(i=0,j=MX;i<3;++i)j=min(j,mp[i][ff[i]]++);
        ans+=j;
    }
    cout<<ans;
}

 

C.题目大意:一个n*m的棋盘,一个棋子一开始在(i,j),每次若在(x,y)能移动到(x-a,y-b),(x+a,y-b),(x-a,y+b),(x+a,y+b)中的一格,问至少几步能移动到(1,1),(1,m),(n,1),(n,m)中的其中一格。(n,m<=10^6)

思路:x,y坐标相互独立,可以先分别求出两种坐标的最小步数,如果一个先到就让另一个反复横跳,注意特判各种无解情况,复杂度O(1)。

#include<cstdio>
#include<algorithm>
using namespace std;
#define INF 1000000000
int n,m,ans=INF,a,b;
void cal(int x,int y,int tx,int ty)
{
    if((tx-x)%a||(ty-y)%b)return;
    int px=(tx-x)/a,py=(ty-y)/b;
    if(px<0)px=-px;if(py<0)py=-py;
    if((px-py)%2)return;
    if(px==py){ans=min(ans,px);return;}
    if(px<py&&x-a<1&&x+a>n)return;
    if(py<px&&y-b<1&&y+b>m)return;
    ans=min(ans,max(px,py));
}
int main()
{
    int i,j;
    scanf("%d%d%d%d%d%d",&n,&m,&i,&j,&a,&b);
    cal(i,j,1,1);cal(i,j,1,m);
    cal(i,j,n,1);cal(i,j,n,m);
    printf(ans<INF?"%d":"Poor Inna and pony!",ans);
}

 

D.题目大意:一个长度为n的小写字母串,支持两种操作:1.将一个子串的所有字母在字母表上循环后移k位(例如a后移2位是c,z后移两位是b);2.查询一个子串内有多少子序列可以通过重组得到一个回文串。(n,操作数<=10^5)

思路:直接用线段树维护区间内各字母出现次数,每次O(26)更新信息,查询时先查出区间内各字母出现次数,枚举一个出现奇数次的字母或全是偶数次的,f1[i]表示i个字母中选出奇数个的方案,f2[i]表示i个字母中选出偶数个的方案,则f1[0]=0,f2[0]=1,每多一个字母我们都可以选或不选,则f1[i]=f2[i]=f1[i-1]+f2[i-1](i>0)(事实上都是2的次幂),然后很容易即可统计答案,复杂度O(26nlogn)。

#include<cstdio>
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
    return x;
}
#define MN 100000
#define L (k<<1)
#define R (k<<1|1)
#define MOD 1000000007
struct node{int l,r,s[26],mk;}t[MN*4+5];
int cnt[26],f1[MN+5],f2[MN+5],lf[26],rf[26];
char s[MN+5];
inline void up(int k){for(int i=0;i<26;++i)t[k].s[i]=t[L].s[i]+t[R].s[i];}
inline void mark(int k,int x)
{
    int i,j,s[26];
    for(i=0;i<26;++i)s[i]=t[k].s[i];
    for(i=0,j=x;i<26;++i,++j>25?j=0:0)t[k].s[j]=s[i];
    if((t[k].mk+=x)>25)t[k].mk-=26;
}
inline void down(int k){if(t[k].mk)mark(L,t[k].mk),mark(R,t[k].mk),t[k].mk=0;}
void build(int k,int l,int r)
{
    if((t[k].l=l)==(t[k].r=r)){++t[k].s[s[l]-'a'];return;}
    int mid=l+r>>1;
    build(L,l,mid);build(R,mid+1,r);up(k);
}
void add(int k,int l,int r,int x)
{
    if(t[k].l==l&&t[k].r==r){mark(k,x%26);return;}
    int mid=t[k].l+t[k].r>>1;down(k);
    if(r<=mid)add(L,l,r,x);
    else if(l>mid)add(R,l,r,x);
    else add(L,l,mid,x),add(R,mid+1,r,x);
    up(k);
}
void query(int k,int l,int r)
{
    if(t[k].l==l&&t[k].r==r){for(int i=0;i<26;++i)cnt[i]+=t[k].s[i];return;}
    int mid=t[k].l+t[k].r>>1;down(k);
    if(r<=mid)query(L,l,r);
    else if(l>mid)query(R,l,r);
    else query(L,l,mid),query(R,mid+1,r);
}
int main()
{
    int n=read(),m=read(),t,l,r,i,ans;
    for(f2[0]=i=1;i<=n;++i)f1[i]=(f1[i-1]+f2[i-1])%MOD,f2[i]=(f1[i-1]+f2[i-1])%MOD;
    scanf("%s",s+1);
    build(1,1,n);
    while(m--)
    {
        t=read();l=read()+1;r=read()+1;
        if(t==1)add(1,l,r,read());
        else
        {
            for(i=0;i<26;++i)cnt[i]=0;query(1,l,r);
            for(i=0;i<26;++i)lf[i]=1LL*(i?lf[i-1]:1)*f2[cnt[i]]%MOD;
            for(i=26;i--;)rf[i]=1LL*(i<25?rf[i+1]:1)*f2[cnt[i]]%MOD;
            for(ans=rf[0]-1,i=0;i<26;++i)
                ans=(ans+1LL*(i?lf[i-1]:1)*(i<25?rf[i+1]:1)%MOD*f1[cnt[i]])%MOD;
            printf("%d\n",ans);
        }
    }
}

 

E.题目大意:询问[a,b]内有多少个数字是k的倍数。(1<=k<=10^18,-10^18<=a<=b<=10^18)

思路:相信是个人都会做,乱写写呗,懒得判各种情况就写了奇怪的代码。

#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
    long long k,a,b,da,db,i;
    cin>>k>>a>>b;
    da=(a/k-5)*k;
    while(da<a)da+=k;
    db=(b/k+5)*k;
    while(db>b)db-=k;
    cout<<(db-da)/k+1;
}

 

F.题目大意:给出一棵n个节点的有根树,要求支持将一棵子树内所有点的权值加上V+d*K(其中d为该点到子树根的距离)和查询一条链上的权值和。(n<=10^5)

思路:树剖一下,线段树多维护一个子树深度和,然后就能维护了,复杂度O(nlogn^2)。

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
    return x;
}
#define MN 100000
#define L (k<<1)
#define R (k<<1|1)
#define MOD 1000000007
struct node{int l,r,s,ds,mk1,mk2;}t[MN*4+5];
struct edge{int nx,t;}e[MN*2+5];
int h[MN+5],en,fa[MN+5],d[MN+5],a[MN+5],s[MN+5],mx[MN+5],f[MN+5],dl[MN+5],dr[MN+5],cnt;
inline void ins(int x,int y)
{
    e[++en]=(edge){h[x],y};h[x]=en;
    e[++en]=(edge){h[y],x};h[y]=en;
}
void pre(int x)
{
    s[x]=1;
    for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[x])
    {
        fa[e[i].t]=x;d[e[i].t]=d[x]+1;
        pre(e[i].t);
        s[x]+=s[e[i].t];if(s[e[i].t]>s[mx[x]])mx[x]=e[i].t;
    }
}
void dfs(int x,int k)
{
    a[dl[x]=++cnt]=d[x];f[x]=k;
    if(mx[x])dfs(mx[x],k);
    for(int i=h[x];i;i=e[i].nx)
        if(e[i].t!=mx[x]&&e[i].t!=fa[x])dfs(e[i].t,e[i].t);
    dr[x]=cnt;
}
inline void up(int k){t[k].s=(t[L].s+t[R].s)%MOD;}
inline void mark(int k,int x1,int x2)
{
    t[k].s=(t[k].s+1LL*x1*(t[k].r-t[k].l+1)+1LL*x2*t[k].ds)%MOD;
    t[k].mk1=(t[k].mk1+x1)%MOD;
    t[k].mk2=(t[k].mk2+x2)%MOD;
}
inline void down(int k)
{
    mark(L,t[k].mk1,t[k].mk2);mark(R,t[k].mk1,t[k].mk2);
    t[k].mk1=t[k].mk2=0;
}
void build(int k,int l,int r)
{
    if((t[k].l=l)==(t[k].r=r)){t[k].ds=a[l];return;}
    int mid=l+r>>1;
    build(L,l,mid);build(R,mid+1,r);
    up(k);t[k].ds=(t[L].ds+t[R].ds)%MOD;
}
void add(int k,int l,int r,int x1,int x2)
{
    if(t[k].l==l&&t[k].r==r){mark(k,x1,x2);return;}
    int mid=t[k].l+t[k].r>>1;down(k);
    if(r<=mid)add(L,l,r,x1,x2);
    else if(l>mid)add(R,l,r,x1,x2);
    else add(L,l,mid,x1,x2),add(R,mid+1,r,x1,x2);
    up(k);
}
int query(int k,int l,int r)
{
    if(t[k].l==l&&t[k].r==r)return t[k].s;
    int mid=t[k].l+t[k].r>>1;down(k);
    if(r<=mid)return query(L,l,r);
    if(l>mid)return query(R,l,r);
    return (query(L,l,mid)+query(R,mid+1,r))%MOD;
}
int query(int x,int y)
{
    int res=0;
    for(;f[x]!=f[y];x=fa[f[x]])
    {
        if(d[f[x]]<d[f[y]])swap(x,y);
        res=(res+query(1,dl[f[x]],dl[x]))%MOD;
    }
    if(dl[x]>dl[y])swap(x,y);
    return ((res+query(1,dl[x],dl[y]))%MOD+MOD)%MOD;
}
int main()
{
    int n,m,rt,i,x,y,z;char o[5];
    n=read();m=read();rt=read();
    for(i=1;i<n;++i)ins(read(),read());
    pre(rt);dfs(rt,rt);
    build(1,1,n);
    while(m--)
    {
        scanf("%s",o);x=read();y=read();
        if(o[0]=='U')z=read(),add(1,dl[x],dr[x],(y-1LL*d[x]*z)%MOD,z);
        else printf("%d\n",query(x,y));
    }
}

 

posted on 2017-04-13 17:13  ditoly  阅读(179)  评论(0编辑  收藏  举报