A.入阵曲
部分分很肥,正解写得常数稍大就会和暴力一个分,考试的时候写什么自己考虑。(滑稽
部分分的循环边界手抖写错了-25 (原本暴力分中的10分都没了啊啊啊)
没写挂的话应该有75,其实就是二维前缀和+暴力枚举点对统计+$a[i][j]$都相等时只枚举子矩形大小再乘上这种大小出现的次数。
正解:$(sum[r]-sum[l-1])\% K=0 \rightarrow sum[r]\% K=sum[l-1]\% K$
枚举行数$i,j$和列数$k$,维护i行和j行之间、k列左侧在%K意义下同余矩阵的个数,用桶来实现。


#include<cstdio> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=650; int n,m; ll K,ans; int a[N][N]; ll sum[N][N],sum1[N],cnt[1000005]; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int main() { n=read();m=read();K=1LL*read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+1LL*a[i][j]; for(int i=0;i<n;i++) for(int j=i+1;j<=n;j++) { cnt[0]=1; for(int k=1;k<=m;k++) { sum1[k]=(sum[j][k]-sum[i][k]+K)%K; ans+=cnt[sum1[k]]; cnt[sum1[k]]++; } for(int k=1;k<=m;k++)cnt[sum1[k]]=0; } cout<<ans<<endl; return 0; }
B.将军令
我考场都能想到的sb贪心。每次取出深度最大且未被覆盖的点,在它的K级祖先上驻扎即可。前者用堆维护,后者直接暴力修改覆盖状态,注意向上修改时不要只遍历和它在一条链上的。
正确性?读者自证不难。(逃


#include<cstdio> #include<iostream> #include<cstring> #include<queue> #define pa pair<int,int> #define re register using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } const int N=100005; int n,K,t; int to[N<<1],nxt[N<<1],head[N],tot; inline void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } int dep[N],fa[N]; priority_queue<pa> q; void dfs1(int x,int deep) { dep[x]=deep; for(re int i=head[x];i;i=nxt[i]) { int y=to[i]; if(!dep[y])dfs1(y,deep+1),fa[y]=x; } return ; } int cover[N],anc,ans; void getan(int x,int rest) { if(!rest||x==1) { anc=x; return ; } getan(fa[x],rest-1); return ; } void dfs2(int x,int rest,int f) { cover[x]=1; if(!rest)return ; for(re int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==f)continue; dfs2(y,rest-1,x); } return ; } int main() { n=read();K=read();t=read(); for(re int i=1;i<n;i++) { int x=read(),y=read(); add(x,y);add(y,x); } dfs1(1,1); for(re int i=1;i<=n;i++) q.push(make_pair(dep[i],i)); while(!q.empty()) { int x=q.top().second; q.pop(); if(cover[x])continue; getan(x,K); //cout<<anc<<endl; dfs2(anc,K,-1); ans++; } cout<<ans<<endl; return 0; }