今天把之前的题目在补一补吧,这场凋惨了呀!
A题,这个题有一个坑点就是他变两次可以都不是0,这样就是NO,我就比较菜,在这个点WA5次
题意:给你两个数组(a,b),问a数组中任意一段连续区间加上一个数k(k大于等于0),使得a和b相等
思路:如果a==b直接就是YES,如果b[i]<a[i]直接就是NO,否则的话就记录下b[i]-a[i]得值,当这个值变了两次以上就是NO,如果变两次则必须有一次为0这样就是YES,否则就是NO
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #include <cmath> 7 8 using namespace std; 9 typedef long long ll; 10 int a[100010],b[100010],c[1010]; 11 int main() 12 { 13 int t; 14 cin >> t; 15 while(t--) 16 { 17 int n; 18 cin >> n; 19 for(int i=1;i<=n;i++) 20 { 21 scanf("%d",&a[i]); 22 } 23 24 for(int i=1;i<=n;i++) 25 { 26 scanf("%d",&b[i]); 27 } 28 int k=0,flag=0,num=0; 29 for(int i=1;i<=n;i++) 30 { 31 if(b[i]<a[i]) 32 { 33 flag=1; 34 } 35 else{ 36 int t = b[i]-a[i]; 37 if(k!=t) 38 { 39 if(k==0||t==0) 40 { 41 k=t; 42 num++; 43 } 44 else if(k!=0&&t!=0) 45 { 46 num=1000; 47 //cout << k<<' '<<t<<endl; 48 } 49 } 50 } 51 } 52 // cout <<num<<endl; 53 if(flag==1) 54 { 55 cout <<"NO"<<endl; 56 } 57 else if(num>2) 58 { 59 cout<<"NO"<<endl; 60 } 61 else{ 62 cout<<"YES"<<endl; 63 } 64 } 65 return 0; 66 }
B题
题意:给你n个数正数表示这个数的绝对值入队,负数表示绝对值出队,必须先入队再出队,同一天一个数只可以入队一次,问给你的n个数的序列可不可以划分为m天,可以的话就输出天数m,和每天各有多少数入队
思路:就是用set来模拟,用map来标记每天入队的人,如果是正数就入队,如果一个数还没出队就又入就直接输出-1,如果是负数就看对里面有没有,没有的话直接-1,有的话就出队直到队列面的数为空时,直接清空map,数量的话就用下标来维护
最后看一下set有没有空,没空的就是-1
这道题我也掉坑了,WA了两发,就是那种最后的时候入队,不出队的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #include <set> 7 #include <map> 8 #include <vector> 9 using namespace std; 10 typedef long long ll; 11 int a[100010]; 12 set<int>p; 13 map<int,int>mp,mmp; 14 vector<int>q; 15 int main() 16 { 17 int n; 18 cin >>n; 19 for(int i=1;i<=n;i++) 20 { 21 scanf("%d",&a[i]); 22 } 23 int d =0,t=0; 24 for(int i=1;i<=n;i++) 25 { 26 if(a[i]>0) 27 { 28 p.insert(a[i]); 29 mp[a[i]]+=1; 30 if(mp[a[i]]>1){ 31 d=-1; 32 break; 33 } 34 } 35 else{ 36 if(mp[-a[i]]==0){ 37 d=-1; 38 break; 39 } 40 else{ 41 int m = a[i]*-1; 42 p.erase(m); 43 if(p.size()==0) 44 { 45 mp.clear(); 46 d++; 47 q.push_back(i-t); 48 t=i; 49 } 50 } 51 } 52 } 53 if(!mp.empty()){ 54 cout<<-1<<endl; 55 return 0; 56 } 57 if(d==-1||d==0) 58 { 59 cout << -1 <<endl; 60 } 61 else{ 62 cout << d <<endl; 63 for(int i=0;i<q.size()-1;i++) 64 { 65 cout<<q[i]<<' '; 66 } 67 cout <<q[q.size()-1]; 68 } 69 return 0; 70 }
C题
题意:就是给你n个糖块,每天最多可一吃m块糖,第几天吃的糖,甜蜜度就乘上第几,让你输出吃(1~n)块糖的最小甜蜜
思路:暴力的想法就是将这些糖按照甜蜜度排一个续序,然后没次都是倒着从第i甜的开始吃依次枚举过去,完全会超时的
我们可以把这个过程好好想一下,当糖果数没有超过m时,就是第一天可以吃完的,不就是糖果从小到大的前缀和吗?
当大于m时,例如当糖果数k = m +1 时,第一个糖果被挤到了第二天去吃,第m+1块糖果要第一天吃,不就是吃m块糖果在上第一颗糖果和第m+1颗糖果吗?
当k = 3*m+2时,就有他就是第3*m +1 颗糖果把第二颗糖果又往后拖一天就是甜蜜度又多加一个第二颗糖果吗同时第m+2颗糖也往后拖了一天,甜蜜度也要加,第2m + 2?还要加上刚刚加进来的第3m+2吗?
这几个圈起来的就是当达到第x*m + y 是 要把从(0~x-1)m +y 的甜蜜度都要加上,因为xm+y由第0天变成了第1天,那么每多加一个m的糖都要往后拖一天,就要加一次
所以a[i] = a[i-1] + a[i] + b[i](i%m的所有小于i的倍数)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cstring> 6 #include <string> 7 #include <vector> 8 #include <set> 9 #include <map> 10 #include <queue> 11 12 using namespace std; 13 const int N = 2e5 +10; 14 typedef long long ll; 15 ll a[N],ans[N],b[N]; 16 int main() 17 { 18 int n,m; 19 cin >> n >> m; 20 for(int i = 1 ; i <= n; i ++) 21 { 22 scanf("%d",&a[i]); 23 } 24 sort(a+1,a+n+1); 25 for(int j = m + 1; j <= n; j++ ) 26 { 27 b[j] = b[j-m] + a[j-m];//预处理第j天要多加的甜蜜度 28 //第j天我们要把所有(j%m)的倍数中小于j的都加一次 29 } 30 for(int i=1;i<=n;i++) 31 { 32 a[i]=a[i-1]+a[i] + b[i]; 33 //b[i]表示第i天除了由第0天变道第一天的其他所哟添加的甜蜜度 34 printf("%lld ",a[i]); 35 } 36 return 0; 37 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cstring> 6 #include <string> 7 #include <vector> 8 #include <set> 9 #include <map> 10 #include <queue> 11 12 using namespace std; 13 const int N = 2e5 +10; 14 typedef long long ll; 15 ll a[N],ans[N],b[N]; 16 int main() 17 { 18 int n,m; 19 cin >> n >> m; 20 for(int i = 1 ; i <= n; i ++) 21 { 22 scanf("%d",&a[i]); 23 24 } 25 sort(a+1,a+n+1); 26 for(int i=1;i<=m;i++) 27 { 28 b[i]=a[i]; 29 } 30 for(int j = m + 1; j <= n; j++ ) 31 { 32 b[j] = b[j-m]+a[j];//预处理第j天要多加的甜蜜度 33 //第j天我们要把所有(j%m)的倍数中小于等于j的都加一次 34 } 35 for(int i=1;i<=m;i++) 36 { 37 a[i]=a[i-1]+a[i]; 38 printf("%lld ",a[i]); 39 } 40 for(int i=m+1;i<=n;i++) 41 { 42 a[i]=a[i-1]+b[i]; 43 //b[i]表示第i天所有添加的甜蜜度 44 printf("%lld ",a[i]); 45 } 46 return 0; 47 }
D题
题意:给出n个点,m条边,如果一组边集里面的最小点u到最大点v有边,则(u~v)之间所有的点都是连通的,问给出的边的情况下最少添加几条边可以变成连通的(给定的有边的点之间存在两点间的所有点都是和着连个点连通的)
思路:最多有2e5个点,所以用vector【2e5】来表示所有点的边集合,然后暴力枚举所有的点,搜索边,如果存在一个点小于当前搜索的点,就要添加一条边
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <cstring> 6 #include <string> 7 #include <map> 8 #include <vector> 9 #include <set> 10 11 using namespace std; 12 typedef long long ll; 13 14 vector<int>G[200010]; 15 int mx = 1,vis[200010]; 16 void dfs(int u) 17 { 18 mx=max(mx,u); 19 vis[u]=1; 20 for(int i=0;i<G[u].size();i++) 21 { 22 if(!vis[G[u][i]]) 23 { 24 dfs(G[u][i]); 25 } 26 } 27 } 28 int main() 29 { 30 int n,m; 31 cin >> n >> m; 32 int ans=0; 33 while(m--) 34 { 35 int u,v; 36 scanf("%d%d",&u,&v); 37 G[u].push_back(v); 38 G[v].push_back(u); 39 } 40 for(int i=1;i<=n;i++) 41 { 42 if(!vis[i]) 43 { 44 if(i<mx)ans++; 45 dfs(i); 46 } 47 } 48 cout << ans << endl; 49 return 0; 50 }
总共做了四个题终结一下,自我感觉C题是最难写的,因为思路不好想,对于A,B,两个题都是比较好的思维题,就是坑点比较多,对于D感觉如果会存边集,敢写,爆搜就完了!