目录
A. Points in Segments
明显的差分即可
void solve(){
cin>>n>>m;
vector<int> a(m+5);
while(n--){
int l,r; cin>>l>>r;
a[l]++,a[r+1]--;
}
vector<int> ans;
for(int i=1;i<=m;i++){
a[i]+=a[i-1];
if(!a[i]) ans.push_back(i);
}
cout<<ans.size()<<endl;
for(auto&v:ans) cout<<v<<' ';
cout<<endl;
return ;
}
B. Obtaining the String
直接暴力交换即可对最前面的进行交换然后接着操作
void solve(){
cin>>n;
string a,b; cin>>a>>b;
string aa(a),bb(b);
sort(aa.begin(),aa.end());
sort(bb.begin(),bb.end());
if(aa!=bb){
cout<<-1<<endl;
return ;
}
int ans=0;
vector<int> res;
for(int i=0;i<n;i++){
if(a[i]!=b[i]){
int pos=0;
for(int j=i+1;j<n;j++){
if(a[j]==b[i]){
pos=j;
break;
}
}
for(int j=pos;j>=i+1;j--){
a[j]=a[j-1];
res.push_back(j);
}
ans+=pos-i;
}
}
cout<<ans<<endl;
for(auto&v:res) cout<<v<<' ';
return ;
}
C. Songs Compression
简单贪心,先全选然后逐渐删去变化最大的即可
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
int x,y; cin>>x>>y;
sum+=x;
w[i]=y-x;
}
sort(w+1,w+1+n);
for(int i=0;i<=n;i++){
sum+=w[i];
if(sum<=m){
cout<<i<<endl;
return ;
}
}
cout<<-1<<endl;
return ;
}
D. Walking Between Houses
k次走完s,首先对于k>s||k*(n-1)<s特判掉,这个时候我们有一个平均数的思维,有些数比平均数多有些是恰好利用这个即可
LL n,s,k;
void solve(){
cin>>n>>k>>s;
if(k>s || k*(n-1)<s) return cout<<"NO"<<endl,void();
LL ans = s/k,more = s%k;;
ans ++ ;
int ok = 0;
int now = 1;
cout<<"YES"<<endl;
for(int i=1;i<=more;i++){
now+=(ok ? -ans : ans);
ok ^= 1;
cout<<now<<' ';
}
ans -- ;
for(int i=1;i<=k-more;k--){
now+=(ok ? -ans : ans);
ok ^= 1;
cout<<now<<' ';
}
return ;
E. Stars Drawing
考虑到我们要找的数十字,一个十字的大小是由左右上下的点的数量决定的所以我们先预处理出来(可以双指针或者是直接继承的方式如下代码)每一个点左右上下连续的点的数量,然后星星就是枚举每一个点找四周最小的即可,接着对于处理这个点是否被使用过我们可以考虑使用二维差分即可
int h[M][M],l[M][M];
char s[M][M];
int L[M][M],R[M][M],up[M][M],down[M][M];
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>s[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(s[i][j]=='*'){
L[i][j]=L[i][j-1]+(s[i][j-1]=='*');
up[i][j]=up[i-1][j]+(s[i-1][j]=='*');
}
for(int i=n;i>=1;i--)
for(int j=m;j>=1;j--)
if(s[i][j]=='*'){
R[i][j]=R[i][j+1]+(s[i][j+1]=='*');
down[i][j]=down[i+1][j]+(s[i+1][j]=='*');
}
vector<TUP> ans;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i][j]=='*'){
int num = min({L[i][j],R[i][j],up[i][j],down[i][j]});
if(num){
ans.push_back({i,j,num});
l[i][j-num]++,l[i][j+num+1]--;
h[i-num][j]++,h[i+num+1][j]--;
}
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
l[i][j]+=l[i][j-1];
h[i][j]+=h[i-1][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(s[i][j]=='*' and !l[i][j] and !h[i][j]){
cout<<-1<<endl;
return ;
}
}
cout<<ans.size()<<endl;
for(auto&[x,y,cnt]:ans) cout<<x<<' '<<y<<' '<<cnt<<endl;
return ;
}
F. Bracket Substring
非常经典的目标字符串出现的题目,我们考虑使用kmp+dp处理,同时考虑这个题目的括号特性我们需要开一个维度来记录当前这个括号匹配到了即可,规定过括号为+1,右括号为负1即可
然后kmp处理出来ne,接着对每一个位置接"("还是")"进行处理,然后dp
我们定义dp为构造了i个,当前括号的匹配值是j,同时匹配到了第k个数
dp[i][j][k],只有j>0才可以接右括号
int dp[M][M][M];
int ne[M];
int g[M][2];
void KMP(){
for(int i=2,j=0;i<=n;i++){
while(j and s[i]!=s[j+1]) j=ne[j];
if(s[i]==s[j+1]) j++;
ne[i]=j;
}
for(int i=0;i<m;i++){
int l=i,r=i;
while(l and s[l+1]!='(') l=ne[l];
while(r and s[r+1]!=')') r=ne[r];
if(s[l+1]=='(') l++;
if(s[r+1]==')') r++;
g[i][1]=l,g[i][0]=r;
}
g[m][0]=g[m][1]=m;
}
void solve(){
cin>>n;
cin>>s; m=s.size();
s=' '+s;
KMP();
dp[0][0][0]=1;
for(int i=0;i<2*n;i++)
for(int j=0;j<=n;j++)// 表示括号的
for(int k=0;k<=m;k++){// 匹配到了第几个
int v=dp[i][j][k];
if(j) dp[i+1][j-1][g[k][0]]=(dp[i+1][j-1][g[k][0]]+v)%mod;
dp[i+1][j+1][g[k][1]]=(dp[i+1][j+1][g[k][1]]+v)%mod;
}
cout << dp[2*n][0][m] << endl;
return ;
}