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})} $