银联高校极客挑战赛 初赛 第二场

 

开场几十分钟后才开始打的,实验室居然锁门了。。。

 

A. 码队GO

左上、右下角为(1,1)、(x,y)的矩阵的大小,dp处理

然后一个裸的二分答案

(1,1) (x,y) (x-k,y-k) 三个点

sum=

update:

题解说O(Tn^3)就是不严谨了。

20*300^3=540000000

这样都说能过!!!

 

如此接近1秒可以跑的数据量,

有时要考虑常数的大小,是否没跑满的情况!然而没有提及。

 

我的第二个代码:

n^2+(n-1)^2+...+1^1 = 1/6 * n*(n+1)*(2n+1)

相当于/3,实际是180901000,已经是极为接近了。

 

估计有些n^3的写法,也有这样的时间复杂度可以除以一个系数的情况。

 

而实际上呢,

有数据可以让它跑满吗?

 

可以的,如

 

 

 

然而出题人有这种闲情逸致弄这样的极限数据吗?

我不认为。。。

就像有些邀请赛,如2019南昌邀请赛。。。

(然而经过常数优化后,633ms过了)

 

搞个快读,多交几次,估计就能过去了。

 

有时也要考虑一下这种类型的情况。。。

 

 

 

另外一个更巧妙的O(n^3)防被卡方法:

右下端点按照可以制造的最大矩阵的大小,从大到小进行处理

避免全为'*'和全为'.'两个极端数据的卡

几十ms

 

 code1:

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 using namespace std;
 9 #define ll long long
10 
11 const double eps=1e-8;
12 const ll inf=1e9;
13 const ll mod=1e9+7;
14 const int maxn=3e2+10;
15 
16 char str[maxn][maxn];
17 int f[maxn][maxn];
18 
19 int main()
20 {
21     int t,n,m,l,r,mid,i,j;
22     bool vis;
23     scanf("%d",&t);
24     while (t--)
25     {
26         scanf("%d%d",&n,&m);
27         for (i=1;i<=n;i++)
28             scanf("%s",str[i]+1);
29 
30         for (i=1;i<=n;i++)
31             for (j=1;j<=m;j++)
32                 f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+(str[i][j]=='.');
33 
34         l=1,r=min(n,m);
35         while (l<=r)
36         {
37             mid=(l+r)>>1;
38             vis=0;
39 
40             for (i=mid;i<=n;i++)
41                 for (j=mid;j<=m;j++)
42                     if (f[i][j]-f[i-mid][j]-f[i][j-mid]+f[i-mid][j-mid]==mid*mid)
43                         vis=1;  ///写成函数形成,遇到则退出true,这样会快一点;但是写起来不方便
44             if (vis)
45                 l=mid+1;
46             else
47                 r=mid-1;
48         }
49         printf("%d\n",r*r);
50     }
51     return 0;
52 }

 

 code2:

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 using namespace std;
 9 #define ll long long
10 
11 const double eps=1e-8;
12 const ll inf=1e9;
13 const ll mod=1e9+7;
14 const int maxn=3e2+10;
15 
16 char str[maxn][maxn];
17 int f[maxn][maxn];
18 
19 int main()
20 {
21     int t,n,m,i,j,k,l,r,g;
22     scanf("%d",&t);
23     while (t--)
24     {
25         scanf("%d%d",&n,&m);
26         for (i=1;i<=n;i++)
27             scanf("%s",str[i]+1);
28 
29         for (i=1;i<=n;i++)
30             for (j=1;j<=m;j++)
31                 f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+(str[i][j]=='.');
32 
33         /**
34         避免全为'*'和全为'.'两个极端数据的卡
35         **/
36 
37         r=0;
38         ///from large to small
39         for (i=n+m;i>r;i--)
40         {
41             for (j=max(1,i-m);j<=n;j++)
42             {
43                 k=i-j;
44                 g=min(j,k);
45                 for (l=r+1;l<=g;l++)    ///r+1来自乐逍大佬提醒
46                     if (f[j][k]-f[j-l][k]-f[j][k-l]+f[j-l][k-l]!=l*l)
47                         break;
48                 if (l!=r+1)
49                     r=l-1;
50             }
51         }
52         printf("%d\n",r*r);
53     }
54     return 0;
55 }
56 /*
57 1
58 2 3
59 ...
60 .**
61 
62 3 4
63 ****
64 ****
65 ****
66 
67 3 4
68 ....
69 ....
70 ....
71 
72 4 4
73 ....
74 ....
75 ....
76 ....
77 */

 

B. 码队弟弟的求和问题

n,m为独立的两部分,相乘即可

接下来是整除分块,对于同一块,余数是一个等差数列

update:

我只是找到了规律,

应该培养推公式的能力。。。

n%i 的数学式子

gcd 的数学式子

 

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <string>
  6 #include <algorithm>
  7 #include <iostream>
  8 using namespace std;
  9 #define ll long long
 10 
 11 const double eps=1e-8;
 12 const ll inf=1e9;
 13 const ll mod=1e9+7;
 14 const int maxn=1e5+10;
 15 
 16 ///sum(sum(i*j*(n mod i)(m mod j)) mod 1e9+7
 17 ///1e9
 18 
 19 int maxv=1e5;
 20 
 21 //int zhi[maxn];
 22 bool vis[maxn];
 23 
 24 ll work(ll n)
 25 {
 26     ll l,r,sum=0,a0,b0,q,g,xx,yy,zz;
 27     for (l=1;l<=n;l=r+1)
 28     {
 29         r=n/(n/l);
 30         if (l==r)
 31             sum+=n%l*l;
 32         else
 33         {
 34             ///a0=l,b0,q,g
 35             a0=l;
 36             b0=n%l;
 37             q=n/l;
 38             g=r-l+1;
 39 
 40             ///0^2+1^2+...
 41             (sum+=a0*b0%mod*g)%=mod;
 42             if (g&1)
 43                 (sum+=b0*g%mod*((g-1)/2))%=mod;
 44             else
 45                 (sum+=b0*(g/2)%mod*(g-1))%=mod;
 46             if (g&1)
 47                 (sum-=a0*q%mod*g%mod*((g-1)/2))%=mod;
 48             else
 49                 (sum-=a0*q%mod*(g/2)%mod*(g-1))%=mod;
 50 
 51             xx=g-1;
 52             yy=g;
 53             zz=2*g-1;
 54             if (xx%2==0)
 55                 xx/=2;
 56             else if (yy%2==0)
 57                 yy/=2;
 58             else
 59                 zz/=2;
 60             if (xx%3==0)
 61                 xx/=3;
 62             else if (yy%3==0)
 63                 yy/=3;
 64             else
 65                 zz/=3;
 66             (sum-=q*xx%mod*yy%mod*zz)%=mod;
 67 //                q*(g-1)*g*(2*g-1)/6
 68             ///sum+=a0*b0*g + b0*g*(g-1)/2 - a0*q*g*(g-1)/2 - q*(g-1)*g*(2*g-1)/6;
 69 
 70 //            sum+=a0*g-q*g*(g-1)/2;
 71         }
 72 //        printf("%lld %lld\n",l,r);
 73     }
 74     return sum;
 75 }
 76 
 77 int main()
 78 {
 79     /*
 80     ///n 最小的质因数
 81     for (i=2;i<=maxv;i++)
 82     {
 83         if (!vis[i])
 84         {
 85             zhi[++cnt_zhi]=i;
 86             for (j)
 87         }
 88     }
 89     */
 90 
 91     ll n,m,i;
 92     ///two parts
 93     scanf("%lld%lld",&n,&m);
 94     printf("%lld",(work(n)*work(m)%mod+mod)%mod);
 95     return 0;
 96 }
 97 /*
 98 1 1
 99 2 2
100 3 3
101 4 4
102 5 5
103 6 6
104 7 7
105 1000000000 1000000000
106 */

 

C. 异世界幻想

菜鸡不会推公式,只能找规律

打表

 

看这:

http://blog.csdn.net/morejarphone/article/details/50677172

https://www.cnblogs.com/dirge/p/5503289.html

 

无根树 & prufer

n^(n-2)

 

update:

我觉得没多少人能按照题解的方法写出来。。。

我感觉更多的是xxx,甚至是yyy。

 

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 using namespace std;
 9 #define ll long long
10 #include <set>
11 
12 const double eps=1e-8;
13 const ll inf=1e9;
14 const ll mod=1e9+7;
15 const int maxn=15;
16 
17 int n,a[maxn],hap[maxn],link[maxn],siz_n;
18 ll sum=0;
19 set<int>se;
20 
21 void judge(int step)
22 {
23     int x,y;
24     if (step==n-1)
25     {
26         x=*se.begin();
27         se.erase(se.begin());
28         y=*se.begin();
29         se.erase(se.begin());
30         link[x]++,link[y]++;
31         for (x=1;x<=n;x++)
32             if (link[x]==1)
33                 sum++;
34         return;
35     }
36     x=*se.begin();
37     se.erase(se.begin());
38     y=a[step];
39     link[x]++,link[y]++;
40     hap[y]--;
41     if (hap[y]==0)
42         se.insert(y);
43     judge(step+1);
44 }
45 
46 void work(int step)
47 {
48     int i;
49     if (step==n-1)
50     {
51         se.clear();
52         memset(hap,0,siz_n);
53         memset(link,0,siz_n);
54         for (i=1;i<=n;i++)
55             hap[a[i]]++;
56         for (i=1;i<=n;i++)
57             if (hap[i]==0)
58                 se.insert(i);
59         judge(1);
60         return;
61     }
62     for (i=1;i<=n;i++)
63     {
64         a[step]=i;
65         work(step+1);
66     }
67 }
68 
69 int main()
70 {
71     for (n=2;n<=10;n++)
72     {
73         siz_n=4*(n+1);
74         sum=0;
75         work(1);
76         printf("n=%d sum=%lld\n",n,sum);
77     }
78     return 0;
79 }
80 /*
81 n=2 sum=2
82 n=3 sum=6
83 n=4 sum=36
84 n=5 sum=320
85 n=6 sum=3750
86 n=7 sum=54432
87 n=8 sum=941192
88 n=9 sum=18874368
89 
90 n * (n-1)^(n-2)
91 */

 

代码

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 using namespace std;
 9 #define ll long long
10 
11 const double eps=1e-8;
12 const ll inf=1e9;
13 const ll mod=998244353;
14 const int maxn=1e5+10;
15 
16 ll mul(ll a,ll b)
17 {
18     ll y=1;
19     while (b)
20     {
21         if (b&1)
22             y=y*a%mod;
23         a=a*a%mod;
24         b>>=1;
25     }
26     return y;
27 }
28 
29 int main()
30 {
31     ll n;
32     scanf("%lld",&n);
33     if (n==1)
34     {
35         printf("1");
36         return 0;
37     }
38 
39     printf("%lld",n*mul(n-1,n-2)%mod);
40     return 0;
41 }
42 /*
43 n=2 sum=2
44 n=3 sum=6
45 n=4 sum=36
46 n=5 sum=320
47 n=6 sum=3750
48 n=7 sum=54432
49 n=8 sum=941192
50 n=9 sum=18874368
51 
52 n * (n-1)^(n-2)
53 */

 

来自群里的大佬解答

 

证明:

1.不同的 大小为n-1的两个无根树,加上一个无根树后,还是无根树。

2.在一个无根树的两个不同的点,加上这个点,唯一与这个点相连的点的度数加一,与其它无根树不一样了。

 

引用另外的大佬一句总结

 

posted @ 2019-07-21 17:01  congmingyige  阅读(312)  评论(0编辑  收藏  举报