牛客练习赛16
A 字典序最大的子序列 > 25960019
一开始潜意识看成了循环,最长子串……
找每个字母最晚出现的位置,那么比它小的字符必须出现在 在它之后的位置
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list> 8 #include <stack> 9 #include <queue> 10 #include <vector> 11 #include <algorithm> 12 #include <iostream> 13 using namespace std; 14 #define ll long long 15 const long maxn=1e6+50; 16 const ll mod=1e9+7; 17 18 char s[maxn]; 19 long a[27],b[27]; 20 21 int main() 22 { 23 long len,i; 24 scanf("%s",s); 25 len=strlen(s); 26 for (i=0;i<=26;i++) 27 a[i]=-1; 28 for (i=0;i<len;i++) 29 a[s[i]-97]=i; 30 b[26]=-1; 31 for (i=25;i>=0;i--) 32 b[i]=max(b[i+1],a[i]); 33 for (i=0;i<len;i++) 34 if (b[s[i]-97+1]<i) 35 printf("%c",s[i]); 36 return 0; 37 } 38 /* 39 dsfasfaowjfwoeijwalgkargkwefaweioewajfwo 40 */
B 漂亮的树 > 25974107
分奇数和偶数,最后的数之间的差值是固定的,如1,2,3,2,1 ; 1,2,2,1
原来的数减去最终的数(以a[1]=x为基准),求出现次数最多的数。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list> 8 #include <stack> 9 #include <queue> 10 #include <vector> 11 #include <algorithm> 12 #include <iostream> 13 using namespace std; 14 #define ll long long 15 const long maxn=1e5+5; 16 const ll mod=1e9+7; 17 18 long a[maxn],b[maxn*2]; 19 20 int main() 21 { 22 long n,r,i,x; 23 scanf("%ld",&n); 24 a[1]=0; 25 for (i=1;i<=(long)(1.0*n/2);i++) 26 a[i+1]=a[i]+1; 27 for (i=n/2+1;i<=n;i++) 28 a[i]=a[n+1-i]; 29 for (i=0;i<=1e5*2;i++) 30 b[i]=0; 31 for (i=1;i<=n;i++) 32 { 33 scanf("%ld",&x); 34 b[x-a[i]+100000]++; 35 } 36 r=0; 37 for (i=0;i<=1e5*2;i++) 38 r=max(r,b[i]); 39 printf("%ld",n-r); 40 return 0; 41 } 42 /* 43 5 44 1 2 3 2 1 45 4 46 1 2 2 1 47 */
C 任意点 > 25961653
若两点的横坐标或纵坐标相等,则它们在同一组,求组数
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list> 8 #include <stack> 9 #include <queue> 10 #include <vector> 11 #include <algorithm> 12 #include <iostream> 13 using namespace std; 14 #define ll long long 15 const long maxn=1e3+5; 16 const ll mod=1e9+7; 17 18 long x[maxn],y[maxn],n; 19 bool vis[maxn]; 20 21 void dfs(long d) 22 { 23 vis[d]=true; 24 long i; 25 for (i=1;i<=n;i++) 26 if ((x[i]==x[d] || y[i]==y[d]) && !vis[i]) 27 dfs(i); 28 } 29 30 int main() 31 { 32 long i,c; 33 scanf("%ld",&n); 34 for (i=1;i<=n;i++) 35 scanf("%ld%ld",&x[i],&y[i]); 36 for (i=1;i<=n;i++) 37 vis[i]=false; 38 c=0; 39 for (i=1;i<=n;i++) 40 if (!vis[i]) 41 { 42 c++; 43 dfs(i); 44 } 45 printf("%ld",c-1); 46 return 0; 47 }
D k进制数 > 25967939
额,其实要是样例没有把解题思路和易错点说得这么清晰,那这道题就是好题了……
纸上做模拟,发现当所有位之和为R,则:
R=0,结果为0,
否则,设L=k-1,
m=R%L,
如果m=0,则结果为L,
否则结果为m。
证明:
对于k进制,
设原来的数的所有位数之和为a,当数加1,
若进b位,则现在的数的所有位数之和为c=a+1-L*b,则c=(a+1)%L。
对结果为0,L和其它 分别求解
结果为0:求0的个数。如0,0,0,1,2,3,0,0,2,0,则f(3)+f(2)+f(1)=3*4/2 + 2*3/2 + 1*2/2.
结果为L,减去上述为0的个数。因为如0,0,0,1,2中的0(1),0(2),0(3),0(1,2),0(1,3),0(2,3),0(3,3),虽然数之和除以L的余数为0,但是不符合条件
结果为0~L-1:
如何求子串和除以L的余数为m
1.x(i)记录前i个数之和,
2. g(i,M)记录所有x(j) [j=1..i]中,余数为(M-b+L)%L的个数,当x(w)=M,以第w位为结尾的子串中,子串和除以L等于b的个数为g(w-1,M)个。
第一维单调递增,可降维。
因为内存限制,所以要进行离散化,余数数目最多为n*2……
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list> 8 #include <stack> 9 #include <queue> 10 #include <vector> 11 #include <algorithm> 12 #include <iostream> 13 using namespace std; 14 #define ll long long 15 const long maxn=1e5+5; 16 const ll mod=1e9+7; 17 18 long a[maxn],x[maxn],g[maxn*2]; 19 map<long,long>f; 20 set<long>s; 21 22 int main() 23 { 24 long k,b,n,i,j,num,nn; 25 ll ans=0; 26 scanf("%ld%ld%ld",&k,&b,&n); 27 for (i=1;i<=n;i++) 28 scanf("%ld",&a[i]); 29 if (b==0) 30 { 31 for (i=1;i<=n;i++) 32 if (a[i]==0) 33 { 34 j=i; 35 while (i!=n && a[i+1]==0) 36 i++; 37 ans=ans+(long long)(i-j+2)*(i-j+1)/2; 38 } 39 printf("%lld",ans); 40 return 0; 41 } 42 else if (b==k-1) 43 { 44 for (i=1;i<=n;i++) 45 if (a[i]==0) 46 { 47 j=i; 48 while (i!=n && a[i+1]==0) 49 i++; 50 ans=ans-(long long)(i-j+2)*(i-j+1)/2; 51 } 52 b=0; 53 } 54 55 k--; 56 s.clear(); 57 x[0]=0; 58 for (i=1;i<=n;i++) 59 { 60 x[i]=(x[i-1]+a[i])%k; 61 s.insert(x[i]); 62 s.insert((x[i]+b)%k); 63 } 64 s.insert(b); 65 set<long>::iterator z; 66 f.clear(); 67 for (z=s.begin(),num=0;z!=s.end();z++,num++) 68 f[*z]=num; 69 for (i=0;i<num;i++) 70 g[i]=0; 71 g[f[b]]=1; 72 for (i=1;i<=n;i++) 73 { 74 ans=ans+(long long)g[f[x[i]]]; 75 g[f[(x[i]+b)%k]]++; 76 } 77 printf("%lld",ans); 78 return 0; 79 } 80 /* 81 7 6 10 82 0 3 0 0 5 0 4 0 0 0 83 84 85 7 6 5 86 0 0 0 0 0 87 88 7 6 6 89 0 0 0 0 0 6 90 91 7 6 8 92 0 0 0 0 2 4 0 0 93 94 7 6 9 95 0 0 0 0 2 4 0 0 6 96 97 10 5 2 98 1 2 99 */
E 求值 > 25970027
求从某个数开始,第一次 数的第i位为1的数的编号,最多有20个(2^20=1048576),从而时间复杂度O(20n)。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list> 8 #include <stack> 9 #include <queue> 10 #include <vector> 11 #include <algorithm> 12 #include <iostream> 13 using namespace std; 14 #define ll long long 15 #define inf 1e9 16 const long maxn=1e5+5; 17 const ll mod=1e9+7; 18 19 long a[maxn],nex[maxn][30]; 20 bool vis[maxn][30],use[1048576+5]; 21 long num[30]; 22 23 int main() 24 { 25 long n,b,i,j,k,g; 26 scanf("%ld",&n); 27 for (i=1;i<=n;i++) 28 { 29 scanf("%ld",&a[i]); 30 j=0; 31 b=a[i]; 32 while (b) 33 { 34 if (b & 1) 35 vis[i][j]=1; 36 else 37 vis[i][j]=0; 38 j++; 39 b>>=1; 40 } 41 } 42 for (j=0;j<20;j++) 43 nex[n+1][j]=inf; 44 for (i=n;i>=1;i--) 45 for (j=0;j<20;j++) 46 if (vis[i][j]) 47 nex[i][j]=i; 48 else 49 nex[i][j]=nex[i+1][j]; 50 51 for (i=0;i<1048576;i++) 52 use[i]=0; 53 for (i=1;i<=n;i++) 54 { 55 g=0; 56 for (j=0;j<20;j++) 57 if (nex[i][j]!=inf) 58 { 59 num[g]=nex[i][j]; 60 g++; 61 } 62 sort(num,num+g); 63 k=a[i]; 64 use[k]=1; 65 for (j=0;j<g;j++) 66 { 67 k=k | a[num[j]]; 68 use[k]=1; 69 } 70 } 71 g=0; 72 for (i=0;i<1048576;i++) 73 if (use[i]) 74 g++; 75 printf("%ld",g); 76 return 0; 77 }
F 选值 > 25960795
先对数排序
用两个变量,求从一个数开始,大于等于该数且差值小于等于d的数的最远编号,这个编号一直是递增的,所以O(n)。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list> 8 #include <stack> 9 #include <queue> 10 #include <vector> 11 #include <algorithm> 12 #include <iostream> 13 using namespace std; 14 #define ll long long 15 const long maxn=1e5+5; 16 const ll mod=1e9+7; 17 18 long a[maxn]; 19 20 int main() 21 { 22 long n,d,i,k; 23 long long r=0,g; 24 scanf("%ld%ld",&n,&d); 25 for (i=1;i<=n;i++) 26 scanf("%ld",&a[i]); 27 k=1; 28 for (i=1;i<=n;i++) 29 { 30 while (k!=n && a[k+1]-a[i]<=d) 31 k++; 32 g=k-i; 33 r=r+g*(g-1)/2; 34 } 35 printf("%lld",r); 36 return 0; 37 }
或者
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <list> 8 #include <stack> 9 #include <queue> 10 #include <vector> 11 #include <algorithm> 12 #include <iostream> 13 using namespace std; 14 #define ll long long 15 const long maxn=1e5+5; 16 const ll mod=1e9+7; 17 18 long a[maxn]; 19 20 int main() 21 { 22 long n,d,i,j,k; 23 long long r=0,g1,g2; 24 scanf("%ld%ld",&n,&d); 25 for (i=1;i<=n;i++) 26 scanf("%ld",&a[i]); 27 k=1; 28 for (i=1;i<=n;i++) 29 { 30 j=i; 31 while (j!=n && a[j+1]==a[i]) 32 j++; 33 k=max(k,j); 34 while (k!=n && a[k+1]-a[i]<=d) 35 k++; 36 g1=j-i+1; 37 g2=k-j; 38 if (g1>=3) 39 r=r+g1*(g1-1)*(g1-2)/6; 40 if (g1>=2 && g2>=1) 41 r=r+g1*(g1-1)/2*g2; 42 if (g1>=1 && g2>=2) 43 r=r+g1*g2*(g2-1)/2; 44 i=j; 45 } 46 printf("%lld",r); 47 return 0; 48 }