A.
两个数组作差判一判就行了
1 #include<bits/stdc++.h> 2 #define maxn 100005 3 using namespace std; 4 int T,n; 5 int a[maxn],b[maxn]; 6 int main() 7 { 8 scanf("%d",&T); 9 while(T--) 10 { 11 scanf("%d",&n); 12 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 13 for(int i=1;i<=n;++i)scanf("%d",&b[i]); 14 for(int i=1;i<=n;++i)a[i]-=b[i]; 15 bool yes=1; 16 for(int i=1;i<=n;++i)if(a[i]>0)yes=0; 17 int cnt=0; 18 for(int i=1;i<=n;++i) 19 { 20 if(a[i]!=0&&a[i-1]==0)cnt++; 21 if(a[i]!=0&&a[i-1]!=0&&a[i]!=a[i-1])yes=0; 22 } 23 if(yes&&cnt<=1)puts("YES"); 24 else puts("NO"); 25 } 26 }
B.
用一个set维护已经出现的正的,一个set维护当天用过的(出现一正一负的)
然后各种边界判一判
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 set<int> s,used; 5 int main() 6 { 7 scanf("%d",&n); 8 bool yes=1; 9 vector<int> Ans;Ans.clear(); 10 Ans.push_back(0); 11 for(int i=1;i<=n;++i) 12 { 13 int x; 14 scanf("%d",&x); 15 if(x<0) 16 { 17 if(!s.count(-x)){yes=0;break;} 18 s.erase(-x),used.insert(-x); 19 } 20 else 21 { 22 if(s.count(x)){yes=0;break;} 23 s.insert(x); 24 } 25 if(s.count(abs(x))&&used.count(abs(x)))yes=0; 26 if(s.empty())Ans.push_back(i),used.clear(); 27 } 28 if(!s.empty())yes=0; 29 if(!yes) 30 { 31 puts("-1"); 32 return 0; 33 } 34 printf("%d\n",Ans.size()-1); 35 for(int i=1;i<Ans.size();++i)printf("%d ",Ans[i]-Ans[i-1]); 36 }
C.
考虑贪心,一定是从小朝大选
然后考虑把哪些放在靠前的天数,一定是较小的那些
然后在\( \bmod m\)意义下维护一下就行了
1 #include<bits/stdc++.h> 2 #define maxn 1000005 3 #define ll long long 4 using namespace std; 5 int n,m; 6 ll a[maxn],s[maxn]; 7 int main() 8 { 9 scanf("%d%d",&n,&m); 10 for(int i=1;i<=n;++i)scanf("%I64d",&a[i]); 11 sort(a+1,a+n+1); 12 ll ans=0; 13 for(int i=1;i<=n;++i) 14 { 15 ans+=s[i%m]; 16 s[i%m]+=a[i]; 17 ans+=a[i]; 18 printf("%I64d ",ans); 19 } 20 }
D.
考虑一定是连续的一段编号连通
那么我们从左往右扫,并用一个并查集维护每个连通块里编号最大的点
然后剩下这段的点都接上去就行了
1 #include<bits/stdc++.h> 2 #define maxn 200005 3 using namespace std; 4 int n,m; 5 int fa[maxn],sz[maxn],mx[maxn]; 6 int find(int x) 7 { 8 while(x!=fa[x])x=fa[x]; 9 return x; 10 } 11 void merge(int u,int v) 12 { 13 if(find(u)==find(v))return; 14 int fu=find(u),fv=find(v); 15 if(sz[fu]<sz[fv])fa[fu]=fv,mx[fv]=max(mx[fv],mx[fu]),sz[fv]+=sz[fu]; 16 else fa[fv]=fu,mx[fu]=max(mx[fu],mx[fv]),sz[fu]+=sz[fv]; 17 } 18 int main() 19 { 20 scanf("%d%d",&n,&m); 21 for(int i=1;i<=n;++i)fa[i]=i,sz[i]=1,mx[i]=i; 22 for(int i=1;i<=m;++i) 23 { 24 int u,v; 25 scanf("%d%d",&u,&v); 26 merge(u,v); 27 } 28 int ans=0; 29 for(int l=1;l<=n;++l) 30 { 31 for(int r=l+1;r<mx[find(l)];++r) 32 { 33 if(find(l)!=find(r))ans++,merge(l,r); 34 } 35 l=mx[find(l)]; 36 } 37 cout<<ans<<endl; 38 }
E.
考虑DP
\(dp[i][j]\)表示第\(i\)个位置被\(j\)号区间覆盖
然后考虑转移:
1.延续这个区间:如果在这个区间内,那么直接延伸,否则用1费延伸
2.更新对称位置:这个点已经被覆盖了,那么到对称位置肯定也一直被覆盖,转移一下取个\(min\)
2.换一个区间:枚举另外一个区间,用另外一个区间,加上花费就行了
1 #include<bits/stdc++.h> 2 #define maxn 85 3 #define maxm 100005 4 using namespace std; 5 int n,m; 6 int X[maxn],S[maxn]; 7 int dp[maxm][maxn]; 8 int main() 9 { 10 scanf("%d%d",&n,&m); 11 for(int i=1;i<=n;++i)scanf("%d%d",&X[i],&S[i]); 12 for(int i=1;i<=n;++i)dp[1][i]=max(0,X[i]-S[i]-1); 13 for(int i=2;i<=m;++i) 14 for(int j=1;j<=n;++j)dp[i][j]=1000000000; 15 for(int i=1;i<m;++i) 16 { 17 for(int j=1;j<=n;++j) 18 { 19 if(i+1<=X[j]+S[j])dp[i+1][j]=min(dp[i+1][j],dp[i][j]); 20 else dp[i+1][j]=min(dp[i+1][j],dp[i][j]+1); 21 if(i<=X[j])dp[min(2*X[j]-i,m)][j]=min(dp[min(2*X[j]-i,m)][j],dp[i][j]); 22 for(int k=1;k<=n;++k)if(k!=j&&i<=X[k]) 23 { 24 if(X[k]-S[k]<=i)dp[i+1][k]=min(dp[i+1][k],dp[i][j]); 25 else dp[i+1][k]=min(dp[i+1][k],dp[i][j]+X[k]-S[k]-(i+1)); 26 } 27 } 28 } 29 int ans=1000000000; 30 for(int i=1;i<=n;++i)ans=min(ans,dp[m][i]); 31 cout<<ans<<endl; 32 }
F.