2019牛客暑期多校训练营(第八场)
B.Beauty Values (dp)
•题意
给你一个序列 a,求序列 a 的任意一个区间 [l,r] 中,元素不同的个数的加和;
•思路
定义 dp[ i ] 表示以 i 为结尾的所有区间所包含的元素不同的数的个数;
即 $dp[i]=\sum_{j=1}^{j <= i}f\{j,i\}$,$f\{j,i\}$指的是[ j , i ]区间不同数的个数;
那么,对于 i 位置的数 ai:
①i 位置为 ai 首次出现的位置:
$dp[i]=dp[i-1]+i$;
为什么是+i?
因为在 [1,i] 比 [1,i-1] 多了个不同的数
同理 [2,i],[3,i]....[i,i]一共多了i个
②[1,i-1] 中 ai 出现的最晚的位置为 j:
$dp[i]=dp[i-1]+i-j$;
为什么-j?
比如x在 2,10,... j位置出现过
那既然j位置出现过也就是在 [j,i-1] 区间出现过,
必然在[j-1,i-1],[j-2,i-1] ... [1,i-1]位置出现过
也就是多算了j次,要 -j
•代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=1e5+5; 5 int pos[maxn]; 6 int a[maxn]; 7 ll dp[maxn]; 8 int main() 9 { 10 int n; 11 cin>>n; 12 dp[1]=1; 13 for(int i=1;i<=n;i++) 14 { 15 cin>>a[i]; 16 if(i>1) 17 dp[i]=dp[i-1]+i-pos[a[i]]; 18 pos[a[i]]=i; 19 } 20 ll ans=0; 21 for(int i=1;i<=n;i++) 22 ans+=dp[i]; 23 cout<<ans<<endl; 24 }
C.CDMA(构造)
•题意
假设序列 s,t 都只含有 n 个元素;
定义 $s\cdot t=\sum_{i=1}^{i<=n}s_i\cdot t_i$ ;
构造一个 m×m 的矩阵 a,其中 m = 2k , 1 ≤k ≤ 10,使其满足:
①矩阵中只包含 -1,1;
②任意不同的两行 a[ i ],a[ j ], a[ i ]·a[ j ] = 0;
•题解
根据 m = 2 , m = 4 的满足条件的矩阵找规律;
m = 2:
$\left( \begin{array}{cc} 1 & 1 \\ 1 & -1 \end{array}\right)$
m = 4:
$\left( \begin{array}{cccc} 1 & 1 & 1 & 1 \\ 1 & -1 & 1 & -1 \\ 1 & 1 & -1 & -1 \\ 1 & -1 & -1 & 1 \\ \end{array}\right)$
m = 4 时,从行,列的中间分开,分成成 4 个 2×2 的子矩阵,你会发现,前三个子矩阵 = (m=2时的矩阵);
最后一个子矩阵 = (m=2时的矩阵取反);
根据上述规律,可以求出 m = 8,16,....,1024 时的满足条件的矩阵;
•代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 string base[2000]; 4 int m; 5 void Slove() 6 { 7 for(int k=2;k<=10;k++) 8 { 9 m=1<<k; 10 for(int i=0;i<m/2;i++) 11 base[i]+=base[i]; ///double 12 for(int i=m/2;i<m;i++) 13 { 14 base[i]=base[i%(m/2)]; 15 16 for(int j=m/2;j<m;j++) 17 base[i][j]=(base[i][j]=='0'?'1':'0'); 18 } 19 } 20 } 21 int main() 22 { 23 int m; 24 cin>>m; 25 base[0]="11"; 26 base[1]="10"; 27 //0代表-1 便于用字符表示 28 29 Slove(); 30 for(int i=0;i<m;i++) 31 for(int j=0;j<m;j++) 32 printf("%d%c",base[i][j]=='0'?-1:1,j==m-1?'\n':' '); 33 }
G.Gemstones(模拟)
•题意
给你一个只包含大写字母的串 s;
如果相邻的三个字符为相同的字母,那么,便可将这三个相同的字母消去;
求最多可以消去多少次;
•思路
用栈模拟
当栈中大于两个时,往里加入时判断是否构成相同三字符,
若能构成则消去,不能构成则继续加入
代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=1e5+5; 5 stack<char> sta; 6 char s[maxn]; 7 int main() 8 { 9 scanf("%s",s+1); 10 int len=strlen(s+1); 11 bool flag; 12 int ans=0; 13 14 for(int i=1;i<=len;i++) 15 { 16 flag=true; 17 while(flag) 18 { 19 flag=false; 20 if(sta.size()>=2) 21 { 22 char a=sta.top(); 23 sta.pop(); 24 char b=sta.top(); 25 sta.pop(); 26 if(s[i]==a&&a==b) 27 { 28 flag=true; 29 i++; 30 ans++; 31 } 32 else 33 { 34 sta.push(b); 35 sta.push(a); 36 37 } 38 } 39 } 40 sta.push(s[i]); 41 } 42 43 printf("%d\n",ans); 44 }