2018.7.14 绍兴一中模拟赛 解题报告(更新ing)

成绩:60+60+30=150(较差,很多该得的分没有拿到)

T1:城市(city)

满分解法:

这道题目说实话还真是挺水的。
按照我的思路,就是两遍DFS,第一遍预处理出每个节点的father深度以及子树大小,第二遍直接扫描每个点求答案。然后就可以水过去了。
然而,我有一个地方忘记开long long了。。。一下少了40分。。。(试求我的心理阴影面积)
代码如下:

#include<bits/stdc++.h>
#define LL long long
#define N 1000000
#define MOD 1000000007
int n,ee=0,fa[N+5],lnk[N+5];
LL ans,dis,tot,Size[N+5];
struct edge
{
    int to,nxt;
}e[2*N+5];
inline char tc()
{
    static char ff[10000],*A=ff,*B=ff;
    return A==B&&(B=(A=ff)+fread(ff,1,10000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0;int f=1;char ch;
    while(!isdigit(ch=tc())) if(ch=='-') f=-1;;
    while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    x*=f;
}
inline void write(LL x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline void add(int x,int y)
{
    e[++ee]=(edge){y,lnk[x]},lnk[x]=ee;
}
inline void dfs1(int x,int Depth)//第一遍DFS预处理
{
    register int i;Size[x]=x,++Depth;
    for(i=lnk[x];i;i=e[i].nxt)
        if(e[i].to^fa[x]) dis+=1LL*Depth*e[i].to,fa[e[i].to]=x,dfs1(e[i].to,Depth),Size[x]+=Size[e[i].to];//预处理出每个节点的father和子树大小,并用dis统计出每个节点到1号节点的距离和(就是这个地方我原本少打了个"1LL*",结果就炸了QwQ)
}
inline void dfs2(int x)
{
    for(int i=lnk[x];i;i=e[i].nxt)
    {
        if(e[i].to^fa[x])
        {
            LL Other=tot-Size[e[i].to],dis_=dis;//Other表示除当前子树外的总人数,dis_备份当前的dis,方便回溯
            (ans+=(1LL*((dis+=Other-Size[e[i].to])%=MOD<<1)*e[i].to)%(MOD<<1))%=MOD<<1,dfs2(e[i].to),dis=dis_;//移动之后,与该子树内每个点的距离减1了,但与该子树外每个点的距离加1了,因此可以快速更新dis,同时更新ans
        }
    }
}
int main()
{
    freopen("city.in","r",stdin),freopen("city.out","w",stdout);
    register int i;int x,y;
    for(read(n),i=1;i<n;i++)
        read(x),read(y),add(x,y),add(y,x);
    tot=(1LL*n*(n+1))>>1,dfs1(1,0);
    ans=dis,dfs2(1),write(((ans>>1)%MOD+MOD)%MOD);//因为两个点之间的距离被重复计算了两次,因此要将最终答案除以2;又因为最后要模一个数,因此在求解过程中我每次模时都将MOD乘了2(例如dfs2中更新ans的时候),最后再将ans除以2去模1倍的MOD
    return 0;
}

T2:人工智障(ai)

60分/70分解法:

很暴力的思想,直接暴力求答案,时间复杂度大概是 O ( l c m ( n , m ) ) ,这样60分就到手了。
当然,也有些大佬暴力得了70分(%%%常数之神hl666%%%)。

满分解法:

满分解法的思路就是将k分解为能整除 l c m ( n , m ) 的部分及其余数。
对于能整除 l c m ( n , m ) 的部分,一个很简单的方法就是暴力求解A和B各自赢的局数。不过,正解则稍微复杂一点。
g = g c d ( n , m ) ,则能与a[i]( 1 i g )匹配的只有b[i+kg](k为自然数)。所以,我们就能快速得到答案,再将答案乘 k / l c m ( n , m ) 即可。
对于余数部分,也可以执行类似操作,不过要注意是否超出范围。
代码如下:

#include<bits/stdc++.h>
#define LL long long
#define N 500000
#define M 500000
using namespace std;
LL n,m,k,a[N+5],b[M+5];
inline char tc()
{
    static char ff[100000],*A=ff,*B=ff;
    return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0;LL f=1;char ch;
    while(!isdigit(ch=tc())) if(ch=='-') f=-1;
    while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    x*=f;
}
inline void write(LL x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline LL gcd(LL x,LL y)
{
    return y?gcd(y,x%y):x;
}
inline LL lcm(LL x,LL y)
{
    return 1LL*x/gcd(x,y)*y;
}
int main()
{
    freopen("ai.in","r",stdin),freopen("ai.out","w",stdout);
    register LL i,j;
    for(read(n),read(m),read(k),i=1;i<=n;read(a[i++]));
    for(i=1;i<=m;read(b[i++]));
    LL g=gcd(n,m),w=lcm(n,m),WinA=0,WinB=0,s[3];
    for(i=1;i<=g;++i)
    {
        s[0]=s[1]=s[2]=0;//统计石头、剪刀、布出现的次数
        for(j=i;j<=n;j+=g) ++s[a[j]];
        for(j=i;j<=m;j+=g) WinA+=s[(b[j]+2)%3],WinB+=s[(b[j]+1)%3];//计算答案
    }
    WinA*=k/w,WinB*=k/w,k%=w;//将答案乘上k/lcm(n,m),并将k向lcm(n,m)取模
    if(k)//如果k不能整除lcm(n,m)
    {
        for(i=1;i<=g;++i)
        {
            s[0]=s[1]=s[2]=0;
            int o=i;//o记录当前的尾部
            for(j=1;j<=(k+n-1)/n;++j)
            {
                ++s[b[o]];
                if(j<=(k-1)/n) ++((o+=n-1)%=m);
            }
            int x=0;
            for(j=i;j^x;++((j+=n-1)%=m),x=i)
            {
                for(register LL p=j;p<=n;p+=m)
                {
                    if(p>(k-1)%n+1) --s[b[o]];//记得判断是否超出范围
                    WinA+=s[(a[p]+1)%3],WinB+=s[(a[p]+2)%3];
                    if(p>(k-1)%n+1) ++s[b[o]];
                }
                ++s[b[++((o+=n-1)%=m)]],--s[b[j]];
            }
        }
    }
    return write(WinA),putchar(' '),write(WinB),0;
}

T3:循环(calc)

30分解法:

纯暴力+一点几乎不起任何作用的小优化的朴素算法,这样就能骗到30分的部分分了。

满分解法:

这题暂时还没有改满,等改满后再更新该部分的题解。

猜你喜欢

转载自blog.csdn.net/chenxiaoran666/article/details/81124155
今日推荐