「训练日志16」 8.11 下坠

T1 入阵曲

  不算很水,看题解后明白不叫水题。

  为什么你想不到正解,这需要你好好想想。

  $n^4$暴力很好想,傻逼二维前缀和完事儿了。然后就是优化了。

  怎么优化?题目的数据范围显然是$n^3$的复杂度,朝着这个方向想,考虑我们可以删掉哪一维呢?

  首先,我们必须要卡出来一段区间,没有固定区间怎么都不行,在有,$++ans$是肯定不行的,我们一定要找出来规律。

  这道题有一个性质,两个数模k相同,那他们相减一定是k的倍数。根据这个性质,我们维护一个桶,记录当前区间总共有模k意义下这个数有多少个,枚举每一列,他们的方案数就是他们可以组成的相同余数的对数,转移即可。

  注意一下,当$x%k==0$时,本身已经和k整除,特判一下,注意$++$顺序。

  小弟不才。

 1 #include<cstdio>
 2 #define LL long long
 3 #define HZOI std
 4 using namespace HZOI;
 5 int n,m,k,ooo;
 6 int rst[1000003],vis[1000003],tail;
 7 LL ans,sm[505][505],t[1000003];
 8 inline int read();
 9 int main()
10 {
11     n=read(),m=read(),k=read();
12     for (int i=1; i<=n; ++i)
13         for (int j=1; j<=m; ++j)
14             sm[i][j]=sm[i-1][j]+sm[i][j-1]-sm[i-1][j-1]+read();
15     for (int i=1; i<=n; ++i)
16         for (int j=i; j<=n; ++j)
17         {
18             for (int g=1; g<=m; ++g)
19             {
20                 ooo=(sm[j][g]-sm[i-1][g]+k)%k;
21                 if (!ooo) ans+=(++t[ooo]);
22                 else ans+=(t[ooo]++);
23                 if (!vis[ooo]) vis[ooo]=1,rst[++tail]=ooo;
24             }
25             while (tail>0) vis[rst[tail]]=0,t[rst[tail--]]=0;
26         }
27     printf("%lld\n",ans);
28 }
29 inline int read()
30 {
31     int nn=0; char cc=getchar();
32     while (cc<'0' or cc>'9') cc=getchar();
33     while (cc>='0' and cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar();
34     return nn;
35 }
入阵曲

 

T2 将军令

  牛逼题,联赛难度,可是我不会做。

  又是贪心题,从儿子开始找,找离他最远的一个可以控制他的祖先,给他点亮,$Dfs$一下,这题就没了。

  这个证明吧,我要找更高的父亲,他能控制的点只多不少,只要我找到了一个最深的叶子节点,往上回溯,到达的最远的父亲的子树一定全部被控制,然后贪就可以了。

  我用的$Dfs$,转移起来很麻烦,也比较难理解,$Bfs$的方法还是$three_D$神仙教给我的。

  主要需要维护好几个东西

  1. 最深的没有被控制的儿子的$depth$ $di$
  2. 向上回溯第一个不能被控制的距离(为负值)$minn$
  3. 向下需要控制的距离$maxx$
  4. 最深儿子$dimax$

  其实最主要的还是$di$,其他三个信息的维护,大部分都是该变量的参与,转移过程很麻烦,兄弟祖先的情况需要很多特判。

  小弟不才。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #define HZOI std
 4 using namespace HZOI;
 5 const int N=1e6+3;
 6 int n,m,opt,ans;
 7 int tt,first[N],vv[N<<1],nx[N<<1];
 8 int vis[N],di;
 9 void Dfs(int ,int );
10 inline void Add(int ,int );
11 inline int read();
12 inline int max(int a,int b) {return a>b?a:b;}
13 inline int min(int a,int b) {return a<b?a:b;}
14 int main()
15 {
16     n=read(),m=read(),opt=read();
17     for (int i=1,x,y; i<n; ++i)
18     {
19         x=read(),y=read();
20         Add(x,y); Add(y,x);
21     }
22     Dfs(1,1);
23     printf("%d\n",ans);
24     return 0;
25 }
26 void Dfs(int k,int depth)
27 {
28     vis[k]=1;
29     di=max(depth,di);
30     int maxdi=depth;
31     int minn=0x3f3f3f3f,maxx=0;
32     for (int i=first[k]; i; i=nx[i])
33     {
34         int ver=vv[i];
35         if (vis[ver]) continue;
36         Dfs(ver,depth+1);
37         maxx=max(di-depth,maxx),
38         minn=min(di-depth,minn);
39         maxdi=max(di,maxdi);
40     }
41     if (maxx+minn<0) {di=depth+minn;return ;}
42     if (k^1 and maxx>=m) {++ans,di=depth-m-1;return ;}
43     if (k==1 and maxx+minn>=0) {++ans;return ;}
44     di=maxdi;
45 }
46 inline void Add(int u,int v)
47 {
48     vv[++tt]=v,nx[tt]=first[u],first[u]=tt;
49 }
50 inline int read()
51 {
52     int nn=0; char cc=getchar();
53     while (cc<'0' or cc>'9') cc=getchar();
54     while (cc>='0' and cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar();
55     return nn;
56 }
将军令

 

  

 

posted @ 2019-08-12 06:37  _LH  阅读(146)  评论(0编辑  收藏  举报