Bestcoder Round #85

A:问一个长度为n小于等于100000的序列是否存在能整除m的连续子段。

前缀和之后,$ S[l,r] = S(r) - S(l-1) $ 取余m后只要查询在S里是否存在出现两次的数值即可。

注意事项:由于是多组数据的题目,一定要把上一组的数字读完,而不是得出了答案直接break!!!!!!

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4
 5 #define N 100010
 6
 7 using namespace std;
 8
 9 int n,m,cnt[N],S[N];
10
11 int main(){
12     int T;
13     scanf("%d",&T);
14     while(T--){
15         memset(cnt,0,sizeof(cnt));
16         scanf("%d%d",&n,&m);
17         cnt[S[0]=0]++;
18         for(int i=1,x;i<=n;i++){
19             scanf("%d",&x);
20             S[i]=(S[i-1]+x)%m;
21             cnt[S[i]]++;
22         }
23         bool flag=0;
24         for(int i=0;i<5000;i++)
25             if(cnt[i]>=2) flag=1;
26         if(!flag) puts("NO");
27         else puts("YES");
28     }
29     return 0;
30 }

B:

Little White plays a game.There are n pieces of dominoes on the table in a row. He can choose a domino which hasn‘t fall down for at most k times, let it fall to the left or right. When a domino is toppled, it will knock down the erect domino. On the assumption that all of the tiles are fallen in the end, he can set the height of all dominoes, but he wants to minimize the sum of all dominoes height. The height of every domino is an integer and at least 1.

认真分析此题目:假设我们推动了一个骨牌,后面的骨牌连续倒下去,那么显然对于第一个骨牌和中间的骨牌,我们要取 (它和下一个骨牌的dist) +1作为其高度,而对于最后一个骨牌我们让其高度为1 。

所以我们耗费一次推动的机会实际上是将第i个骨牌 dist(i,i+1)+1 的高度改为了 1,答案减小了dist(i,i+1)。

得到解法:对dist(i,i+1) 从小到大排序,取后 K-1 dist值,将其删去。

$ Ans = \sum{dist(i,i+1) (未被删去的dist)} + n $

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5
 6 #define N 100010
 7 #define LL long long
 8
 9 using namespace std;
10
11 int n,K;
12 int a[N];
13
14 int main(){
15     int T;
16     cin>>T;
17     while(T--){
18         cin>>n>>K;
19         LL ans=(LL)n;
20         n--; K--;
21         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
22         sort(a+1,a+n+1);
23         for(int i=1;i<=n-K;i++) ans+=(LL)a[i];
24         cout << ans << endl;
25     }
26     return 0;
27 }

C:

Given a number x, ask positive integer y≥2, that satisfy the following conditions:
1. The absolute value of y - x is minimal
2. To prime factors decomposition of Y, every element factor appears two times exactly.

分析这道题,关键要想到

1.与其求 $ y $,不如求 $ \sqrt{y} $,这样原先的 $ 10^{18} $ 就变为了 $ 10^9 $,这样就能够暴力质因数分解,判定一个数字是否满足条件了。

2.素数定理可知 $ \pi(x) - \pi(x-1) \approx O(lnx) $

然后暴力求解。

注意事项:

1.在调用 $ sqrt(n) $ 时,含有较大的误差,所以取 $ sqrt(n)+0.5 $

2.在执行 $ if(A() || B()) $ 时如果 $ A() = true $,那么就无法执行$ B() $了,具体表现在代码的 48,49 行。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5
 6 #define LL long long
 7 #define sqr(x) ((x)*(x))
 8
 9 using namespace std;
10
11 LL n,ans;
12
13 LL min(LL a,LL b){
14     if(a<b) return a;
15     return b;
16 }
17
18 LL Abs(LL x){
19     if(x<0) return -x;
20     return x;
21 }
22
23 bool check(LL x){
24     if(x<2) return 0;
25     LL nt=x;
26     for(LL i=2;i*i<=nt;i++)
27         if(x%i==0){
28             x/=i;
29             if(x%i==0) return 0;
30         }
31     ans = min(ans, Abs(n-sqr(nt)));
32     return 1;
33 }
34
35 int main(){
36     int T;
37     cin>>T;
38     while(T--){
39         cin>>n;
40         ans = 0x3f3f3f3f3f3f3f3fLL;
41         LL m = (LL)(sqrt(n)+0.5);
42         if(check(m)){
43             cout << Abs(n-sqr(m)) << endl;
44             continue;
45         }
46         bool flag=0;
47         for(LL t=1;!flag;t++){
48             if(check(m+t)) flag=1;
49             if(check(m-t)) flag=1;
50             if(flag){
51                 cout << ans << endl;
52                 break;
53             }
54         }
55     }
56     return 0;
57 }

D:

Little White recently likes playing Tower Defence. She wants to make a map. The map is an undirected graph which has n vertices(graph may not connect).The length of each edge is 1.The shortest distance of vertice 1 to any other vertices is not equal to k.She wants to know how many graphs which satisfy all these conditions.If two vertices is disconnected, the distance between them is infinite.

本套题目中的压轴题,和之前做过的多校联盟,求二分图个数的题目很像。

但是由于引入了最短路,还是真的很难想呀。

分析此题目:如果不存在长度为K的最短路,那么根据最短路算法可知一定不存在长度大于K的最短路,原题转化为求1到任意点最短路小于K的无向图的个数。

比较新奇的状态:

$f(i,j,k)$ 表示有 i 个点和 1相连(类比多校),各个点到1最长的最短路为 j ,有k个点到1的距离为j的方案数。

为什么要有第三维状态呢?

因为根据最短路算法的流程,我们可以知道任意的$ dist(i) = K $,都是由一个$ dist(j) = K-1 $转移来的,而如果我们只留下在从 1 出发的最短路上面的边,那么原图就变为了一个以$ dis(i) $ 为层编号的分层图。

深入发掘其性质,对于所有的无向图的边可以如下分类:

1.第i层连向第i-1层的边

2.第i层之内随意连接的边

而要满足相应的最短路情况,还要:

对于任意的第i层的点,必然要至少连向第i-1层一条边。

所以可以考虑dp转移了

$$ f(i+t,j+1,t) =  \sum f(i,j,k) * C_{n-i}^t * (2^k - 1)^t * 2^{\frac{t(t-1)}{2}} $$

初始状态为:

$$ f(1,0,1) = 1 $$

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4
 5 #define P 1000000007
 6 #define LL long long
 7 #define N 71
 8
 9 using namespace std;
10
11 int n,K;
12 int f[N][N][N],C[N][N];
13
14 int add(int a,int b){
15     if(a+b>=P) return a+b-P;
16     return a+b;
17 }
18
19 int mul(int a,int b){
20     return a*(LL)b%(LL)P;
21 }
22
23 int qpow(int x,int n){
24     int ans=1;
25     for(;n;n>>=1,x=mul(x,x)) if(n&1) ans=mul(ans,x);
26     return ans;
27 }
28
29 int S(int t){
30     if(t==0) return 1;
31     return qpow(2, (t*(t-1))/2);
32 }
33
34 int main(){
35     memset(f,0,sizeof(f));
36     int T,tmp;
37     cin>>T;
38     C[0][0]=1;
39     for(int i=1;i<N;i++){
40         C[i][0]=1;
41         for(int j=1;j<=i;j++){
42             C[i][j] = add(C[i-1][j-1],C[i-1][j]);
43         }
44     }
45     while(T--){
46         memset(f,0,sizeof(f));
47         cin>>n>>K;
48         int ans=0;
49         f[1][0][1]=1;
50         for(int i=1,j,k,t;i<=n;i++)
51             for(j=0;j<min(i,K);j++)
52                 for(k=1;k<=i;k++){
53                     if(!f[i][j][k]) continue;
54                     ans = add(ans, mul(f[i][j][k],S(n-i)) );
55                     for(t=1;t<=n-i;t++){
56                         tmp = mul(f[i][j][k],C[n-i][t]);
57                         tmp = mul(tmp, qpow( (qpow(2,k)-1LL+(LL)P)%P, t ) );
58                         tmp = mul(tmp, S(t));
59                         f[i+t][j+1][t] = add(f[i+t][j+1][t], tmp);
60                     }
61                 }
62         cout << ans << endl;
63     }
64 }

Little White learned the greatest common divisor, so she plan to solve a problem: given x, n,
query $$ \sum_{a=1}^n {\sum_{b=1}^n {gcd(x^a-1,x^b-1)}} $$

非常简单的题目,让我们来考虑一下加强版题目

query $$ \sum_{a=1}^n {\sum_{b=1}^m {gcd(x^a-1,x^b-1)}} $$

$$ \sum_{a=1}^n {\sum_{b=1}^m {(x^a-1,x^b-1)}} $$

首先有:$ (x^a-1,x^b-1) = x^{(a,b)}-1 $
然后,原式变为:
$ \sum_{a=1}^n {\sum_{b=1}^m {x^{(a,b)}}}-nm $

$ \sum_{a=1}^n {\sum_{b=1}^m {x^{(a,b)}}}$ = $\sum_{d=1}^n{\sum_{a=1}^{[\frac{n}{d}]}\sum_{b=1}^{[\frac{m}{d}]}[(a,b)=1]}$ =
$ \sum_{d=1}^n{ x^d \cdot \sum_{i=1}^{[\frac{n}{d}]}{u(i) \cdot [\frac{n}{id}] \cdot [\frac{m}{id}]}} $ =
记 $T = id$
原式 = $ \sum_{T=1}^{n}{[\frac{n}{T}] \cdot [\frac{m}{T}] \cdot \sum_{d|T}}{ x^d \cdot u(\frac{T}{d})} $

时间: 2024-08-18 20:09:28

Bestcoder Round #85的相关文章

HDU 5778 abs(暴力枚举)——BestCoder Round #85 1003

传送门 abs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1474    Accepted Submission(s): 511 Problem Description Given a number x, ask positive integer y≥2, that satisfy the following condition

BestCoder Round #85 sum

大晚上的更一道下午的水题吧.(虽然WA了好多次= =,但真实情况是我比较水) 描述 Given a sequence, you're asked whether there exists a consecutive subsequence whose sum is divisible by m. output YES, otherwise output NO. 输入 The first line of the input has an integer T (1≤T≤10), which repr

BestCoder Round #85(ZOJ1569尚未验证)

A题 子序列和啊,就要想到前缀和的差.这个转换一定要!记着!那么i到j的一段子序列和Sij%m ==  0就等价于(Sj-Si-1)%m == 0 了,那么什么意思呢?就是如果有两段前缀和%m的模是一样的,那么是不是就存在着一段子序列满足条件了,然后注意一下边边角角应该就没问题了.因为ZOJ坏掉了,所以我尚未验证以下答案的ans是否就是满足条件的序列总数!移步ZOJ1569自行验证. 1 #include <cstdio> 2 #include <set> 3 #include &

HDU 5776 sum (BestCoder Round #85 A) 简单前缀判断+水题

分析:就是判断简单的前缀有没有相同,注意下自身是m的倍数,以及vis[0]=true; #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <map> #include <queue> #include <vect

HDU5777 domino (BestCoder Round #85 B) 思路题+排序

分析:最终的结果肯定会分成若干个区间独立,这些若干个区间肯定是独立的(而且肯定是一边倒,左右都一样) 这样想的话,就是如何把这n-1个值分成 k份,使得和最小,那么就是简单的排序,去掉前k大的(注意longlong) #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> #include <algorithm&

HDU 5578 abs (BestCoder Round #85 C)素数筛+暴力

分析:y是一个无平方因子数的平方,所以可以从sqrt(x)向上向下枚举找到第一个无平方因子比较大小 大家可能觉得这样找过去暴力,但实际上无平方因子的分布式非常密集的,相关题目,可以参考 CDOJ:无平方因子数 http://acm.uestc.edu.cn/#/problem/show/618 这个题和CDOJ的题虽然不一样,但是可以从CDOJ发现这种数是很多的 官方题解:官方题解说这个无平方因子的枚举量在logn级别,可见非常小 #include <cstdio> #include <

HDU5579 Tower Defence (BestCoder Round #85 D) 计数dp

分析(官方题解): 一点感想:(这个题是看题解并不是特别会转移,当然写完之后看起来题解说得很清晰,主要是人太弱 这个题是参考faebdc神的代码写的,说句题外话,很荣幸高中和faebdc巨一个省,虽然本弱渣高中都没搞过oi) 最短路不等于k,所以根本不存在最短路>=k的,因为存在的话,由最短路知识可知,k+1一定是由k更新过来的,矛盾 所以最短路不等于k,即最短路小于k 然后就是不管是多校还是bc,都能碰到有关图的计数类的dp问题,比如2016多校1的刚性图,计算连通二分图的数量 这个题是计算无

HDU5780 gcd (BestCoder Round #85 E) 欧拉函数预处理——分块优化

分析(官方题解): 一点感想: 首先上面那个等式成立,然后就是求枚举gcd算贡献就好了,枚举gcd当时赛场上写了一发O(nlogn)的反演,写完过了样例,想交发现结束了 吐槽自己手速慢,但是发了题解后发现,这题连O(n)欧拉函数前缀和的都卡了,幸亏没交,还是太年轻 对于官方题解说sqrt(n)优化(其实就是n/(小于n一段数)结果是一样的,也不算什么分块),还是很简单的,做反演题的时候看到过很多,只是忘记了 如果不会请看这篇解题报告http://wenku.baidu.com/view/fbe2

BestCoder Round #4 前两题 hdu 4931 4932

第一题太水了.. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int a[6]; 7 int main(){ 8 int cas; 9 scanf( "%d", &cas ); 10 while( cas-- ){ 11 for( int i = 0; i <