11.13多校联训


T1 maware

Sol
显然的60分做法是直接维护二维前缀和,复杂度\(\mathcal{O}(n^4)\)
看范围像是\(\mathcal{O}(n^3\log n)\),很容易发现只有矩阵外的1个数能整除全部数个数的时候有可能有解。因数个数在随机情况下期望\(\log n\)个,所以可以枚举因数,然后枚举上下边界跑two-pointers就可以\(\mathcal{O}(n^3\log n)\)通过此题啦!
Code

#include
using namespace std;
namespace io
{
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
        return f?x:-x;
    }
    inline void print(int x)
    {
        static int s[40],slen;slen=0;
        if(x==0){putchar('0');return;}
        if(x<0)x=-x,putchar('-');
        while(x){s[++slen]=x%10;x/=10;}
        for(int i=slen;i;i--)putchar('0'+s[i]);
        return;
    }
}
using namespace io;
const int maxn=210;
int sum[maxn][maxn];
int T,n,q[40010],mxt,s,ans;
int main()
{
    freopen("maware.in","r",stdin);
    freopen("maware.out","w",stdout);
    T=read();
    while(T--)
    {
        memset(q,0,sizeof(q));
        n=read();s=0;ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)sum[i][j]=sum[i][j-1]+read();
            s+=sum[i][n];
        }
        int cnt=0;
        for(int k=0;k=q[i])ret+=r-l;
                }
            }
            if(ret)printf("%d %d\n",k/(s-k),ret);
        }
    }
    return 0;
}

T2 irori

我是傻逼,skip。

T3 yaya

Sol
为啥月球探测器会思考这种问题
题解的线段树确实没算明白。考场上写的前半段。
考虑先处理出初始的答案。然后每次修改暴力维护影响到的答案,查询直接\(\mathcal{O}(1)\)
修改一个数\(x\),它能影响到的点可以反向计算,也就是\(2x,2x+1,3x,3x+1,3x+2···,wx+w-2,wx+w-1\)。影响的点数量是\(\mathcal{O}(w^2)\)的。
有可能有多层影响,但是每次的\(x\)至少翻倍。而且按照dijkstra的思路,使用优先队列,每个点最多访问一次。最终单次修改复杂度上限我算出来是\(\mathcal{O}(\log ^2n*w^2)\)实际还远小于这个数。而且每次尝试都只有一个if,常数很小。稳过前60分,至于后面那25分怎么来的我不清楚,但是题解好像有证明复杂度上限更低,我没看懂。
Code

#include
using namespace std;
const int maxn=50010;
namespace io
{
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
        return f?x:-x;
    }
    inline void print(int x)
    {
        static int s[40],slen;slen=0;
        if(x==0){putchar('0');return;}
        if(x<0)x=-x,putchar('-');
        while(x){s[++slen]=x%10;x/=10;}
        for(int i=slen;i;i--)putchar('0'+s[i]);
        return;
    }
}
using namespace io;
int c[maxn];
int ans[maxn];
int n,w,q;
priority_queue,greater >qu;
bool vis[maxn];
int main()
{
    freopen("yaya.in","r",stdin);
    freopen("yaya.out","w",stdout);
    n=read();w=read();q=read();
    for(int j=1;j<=n;j++)
    {
        int sq=sqrt(j);
        for(int i=1;i<=sq;i++)
        {
            if(j%i==0)c[j]+=2;
        }
        if(sq*sq==j)c[j]--;
        ans[j]=1000000000;
        for(int i=2;i<=w;i++)
        {
            ans[j]=min(ans[j],ans[j/i]);
        }
        ans[j]+=c[j];
    }
    while(q--)
    {
        int opt=read(),x=read();
        if(opt==1)
        {
            ans[x]--;c[x]--;
            vis[x]=1;qu.push(x);
            while(!qu.empty())
            {
                int now=qu.top();qu.pop();
                vis[now]=0;
                bool flag=0;
                for(int i=2;i<=w;i++)
                {
                    for(int j=0;jn)
                        {
                            flag=1;break;
                        }
                        if(ans[now]+c[to]

T4 komurasaki

我只会20分暴力加小剪枝。能把subtask2过掉一半已经很满意了。
暴力直接枚举当前点取什么数,然后更新后面的点的限制条件。
剪枝思路很简单:一个点如果根本没有边与它相连,那它随便取,可以减少递归层数。