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过掉一半已经很满意了。
暴力直接枚举当前点取什么数,然后更新后面的点的限制条件。
剪枝思路很简单:一个点如果根本没有边与它相连,那它随便取,可以减少递归层数。