Codeforces Round #546 (Div. 2)
A. Nastya Is Reading a Book
题意:书分为n个章节 给出连续的章节页码 给出当前页数 问有多少章没有看完
思路 :直接模拟即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=100+5; 4 int l[maxn],r[maxn]; 5 int main(){ 6 int n; 7 scanf("%d",&n); 8 for(int i=0;i<n;i++)scanf("%d%d",&l[i],&r[i]); 9 int ans=0; 10 int p; 11 scanf("%d",&p); 12 for(int i=0;i<n;i++){ 13 if(p>=l[i]&&p<=r[i]){ 14 15 {cout<<n-i;return 0;} 16 } 17 } 18 cout<<0<<endl; 19 return 0; 20 }
B. Nastya Is Playing Computer Games
题意:有n个井盖 每个井盖上面都有一块石头 怪力girl 可以执行 以下操作:把一块石头扔到任意一个井盖上 移动一步 问最小几个操作达成全部井盖都被翻开过的成就
思路:肯定要重复走一段路 直接选择短的那段路重复走即可 并且N>=2 必有 扔3次石头的操作 然后就每次把石头扔到一起即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=100+5; 4 int main(){ 5 int n,k; 6 scanf("%d%d",&n,&k); 7 printf("%d\n",min(n-k,k-1)+3*(n-2)+6); 8 return 0; 9 }
C. Nastya Is Transposing Matrices
题意 给出两个矩阵A B 可以随便选择A的子矩阵转置 可以操作任意次 问A有没有可能变成B
思路:每次转置 斜线上(从左下到右上的线)的元素都是不变的 直接比较斜线上的元素即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=500+5; 4 int a[maxn][maxn],b[maxn][maxn]; 5 multiset<int>x[maxn*10],y[maxn*10]; 6 int main(){ 7 int n,m; 8 scanf("%d%d",&n,&m); 9 10 for(int i=0;i<n;i++){ 11 for(int j=0;j<m;j++)scanf("%d",&a[i][j]); 12 } 13 14 for(int i=0;i<n;i++){ 15 for(int j=0;j<m;j++)scanf("%d",&b[i][j]); 16 } 17 for(int i=0;i<n;i++){ 18 for(int j=0;j<m;j++){ 19 x[i+j].insert(a[i][j]); 20 y[i+j].insert(b[i][j]); 21 } 22 } 23 int flag=1; 24 for(int i=0;i<=n+m;i++){ 25 if(x[i]!=y[i]){flag=0;break;} 26 } 27 if(flag)printf("YES\n"); 28 else printf("NO\n"); 29 30 return 0; 31 }
D. Nastya Is Buying Lunch
题意:有n个人在排队 给出m个单向边 满足单向边的(要求相邻)即可换位置 问 从队伍的最后一名最多能前进多少个位置
思路:这题的方法很巧妙 以整体处理局部,表示局部状态的思想 类似于 不同数字 的序列 a1 a2 a3 ...an 只要max-min+1==n 那么这个序列就是1--n没有重复数字的序列
而本题 使用cnt[p] 表示p后面有多少个可以和p换位置的 如果 cnt[p]==n-i-ans(ans表示递推到当前位置时,有多少个可以换位置的) 那么P就可以换位置 ans++即可 如果p不能换位置
那么就把与p相连的在p前面的cnt++ (这里循环里面是把前后都更新了,因为更新排在后面的没有影响,所以为了减少代码量可以直接也更新)也就是前面的可以和p换位置的cnt要更新
最后即可得到最后答案
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3e5+5; 4 int p[maxn]; 5 int cnt[maxn]; 6 vector<int>q[maxn]; 7 int main(){ 8 int n,m; 9 scanf("%d%d",&n,&m); 10 int tmp; 11 for(int i=1;i<=n;i++){ 12 scanf("%d",&p[i]); 13 } 14 15 int x,y; 16 for(int i=0;i<m;i++){ 17 scanf("%d%d",&x,&y); 18 q[y].push_back(x); 19 } 20 for(int i=0;i<q[p[n]].size();i++){ 21 cnt[q[p[n]][i]]++; 22 } 23 int ans=0; 24 for(int i=n-1;i>=1;i--){ 25 if(n-i-ans==cnt[p[i]])ans++; 26 else { 27 for(int j=0;j<q[p[i]].size();j++){ 28 cnt[q[p[i]][j]]++; 29 } 30 } 31 } 32 cout<<ans<<endl; 33 return 0; 34 }
E. Nastya Hasn't Written a Legend
题意:给出一个n个元素的序列a n-1个元素的序列k 有以下操作:1.将a[i]+x 若a[i]+k[i]> a[i+1] a[i+1]就变成a[i]+k[i] 并且拿新的a[i+1]+k[i+1]和a[i+2]进行对比重复上述操作
2.计算 l 到r的和
思路:明显是一道线段树的题目 关键在于如何转换条件到可以用线段树维护 (第一次做这种类型的题目,所以直接上了题解)
贴上了cf的题解:https://codeforces.com/blog/entry/65905
我在此 做一个翻译机
将a 序列转换成b序列 如果b[i]加上x后 b[i]>b[i+1]那么b[i+1]=b[i]以此类推 ,这样就把不确定不相等的值k给隐藏掉了 妙啊 那么只要找到第一个位置 b[pos]>=b[i]+x pos之前到加的第一个元素都会变成
b[i]+x 这样就可以很方便地用线段树维护鸟 这里找位置使用二分 用线段树维护一个最大值 即可二分 因为求的是b 序列 b=a[i]-t[i] 所以 sigma(b[l,r])=sigma[a[l,r]]-sigma(t[l,r])=> sigma(a[l,r])=sigma(b[l,r]+t[l,r]) t用前缀和即可O(1)用b 算出a
1 #include<bits/stdc++.h> 2 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++) 3 #define MS(arr,arr_value) memset(arr,arr_value,sizeof(arr)) 4 #define F first 5 #define S second 6 #define pii pair<int ,int > 7 #define mkp make_pair 8 #define pb push_back 9 using namespace std; 10 typedef long long ll; 11 const int inf =0x3f3f3f3f; 12 const int maxn=1e5+5; 13 ll laz1[maxn<<2],laz2[maxn<<2],sum[maxn<<2],maxnum[maxn<<2],sum1[maxn],sum2[maxn]; 14 ll a[maxn],k[maxn]; 15 int n,q; 16 void mdf(int o,int l,int r,ll v){ 17 sum[o]=(r-l+1)*v; 18 laz1[o]=v; 19 maxnum[o]=v; 20 } 21 void push_up(int o){ 22 sum[o]=sum[o<<1|1]+sum[o<<1]; 23 maxnum[o]=max(maxnum[o<<1],maxnum[o<<1|1]); 24 } 25 void build(int o,int l,int r){ 26 laz1[o]=-inf; 27 if(l==r){ 28 maxnum[o]=sum[o]=a[l]; 29 return ; 30 } 31 int mid=l+r>>1; 32 build(o<<1,l,mid); 33 build(o<<1|1,mid+1,r); 34 push_up(o); 35 } 36 void push_down(int o,int l,int r){ 37 if(laz1[o]!=-inf){ 38 int mid=l+r>>1; 39 mdf(o<<1,l,mid,laz1[o]); 40 mdf(o<<1|1,mid+1,r,laz1[o]); 41 laz1[o]=-inf; 42 } 43 } 44 void update(int o,int l,int r,int x,int y,ll v){ 45 if(x>y)return ; 46 if(l>=x&&y>=r){ 47 mdf(o,l,r,v); 48 return ; 49 } 50 int mid=l+r>>1; 51 push_down(o,l,r); 52 if(mid>=x)update(o<<1,l,mid,x,y,v); 53 if(mid+1<=y)update(o<<1|1,mid+1,r,x,y,v); 54 push_up(o); 55 } 56 ll query(int o,int l,int r,int x,int y){ 57 if(x>y)return 0; 58 if(x<=l&&r<=y){ 59 return sum[o]; 60 } 61 int mid=l+r>>1; 62 ll ans=0; 63 push_down(o,l,r); 64 if(mid>=x)ans+=query(o<<1,l,mid,x,y); 65 if(mid+1<=y)ans+=query(o<<1|1,mid+1,r,x,y); 66 return ans; 67 } 68 ll querymax(int o,int l,int r,int x,int y){ 69 if(x>y)return -inf; 70 if(l>=x&&r<=y)return maxnum[o]; 71 int mid=l+r>>1; 72 push_down(o,l,r); 73 if (mid < x) 74 return querymax(o << 1 | 1,mid + 1,r,x,y); 75 if (mid + 1 > y) 76 return querymax(o << 1,l,mid,x,y); 77 return max(querymax(o << 1,l,mid,x,y),querymax(o << 1 | 1,mid + 1,r,x,y)); 78 79 } 80 char s[20]; 81 int u,v; 82 int main(){ 83 scanf("%d",&n); 84 FOR(i,1,n)scanf("%lld",&a[i]); 85 FOR(i,1,n-1)scanf("%lld",&k[i]); 86 for(int i=1;i<=n-1;i++){ 87 sum1[i]=sum1[i-1]+k[i]; 88 a[i+1]-=sum1[i]; 89 sum2[i]=sum1[i]+sum2[i-1]; 90 } 91 build(1,1,n); 92 scanf("%d",&q); 93 while(q--){ 94 scanf("%s",&s); 95 scanf("%d%d",&u,&v); 96 if(s[0]=='+'){ 97 int left=u,right=n,ans=-1; 98 ll tmp=querymax(1,1,n,u,u); 99 100 while(left<right){ 101 int mid=left+right+1>>1; 102 if(querymax(1,1,n,u+1,mid)>=tmp+v){ 103 right=mid-1; 104 } 105 else left=mid; 106 } 107 update(1,1,n,u,left,tmp+v); 108 109 } 110 else { 111 printf("%lld\n",query(1,1,n,u,v)+sum2[v-1]-sum2[max(0,u-2)]); 112 } 113 114 } 115 }