A.Codehorses T-shirts
原题链接:CF1000A Codehorses T-shirts
题意:
给定个目标尺寸和个现有尺寸,每次只能改变现有尺寸中的一个字符,问变换多少次才可以满足需求
分析:
因为最终一定可以将现有的尺寸变换到目标尺寸,用两个标记现有尺寸和目标尺寸,遍历现有尺寸,如果现有尺寸的数量大于目标尺寸,那么多出来的数量一定是需要变到其余少的目标尺寸中去的,多出来的数量和就是答案。
代码:
#include<bits/stdc++.h> using namespace std; map<string,int> mp1,mp2; int main() { int n; cin>>n; for(int i=0;i<n;++i) { string input; cin>>input; mp1[input]++; } for(int i=0;i<n;++i) { string input; cin>>input; mp2[input]++; } int cnt=0; for(auto i=mp1.begin();i!=mp1.end();++i) { if(mp2[i->first]<i->second)cnt+=i->second-mp2[i->first]; } cout<<cnt<<endl; return 0; }
B.Alphabetic Removals
原题链接:CF999C Alphabetic Removals
题意:
给定字符串,通过如下操作从字符串中移除个字符:移除字符串中的字符,如果移除的数量没到个,那么继续这个操作,如果字符串中没有,那么就继续对字符进行这个操作,字符移除完后同理。
分析:
模拟。
代码:
#include<bits/stdc++.h> using namespace std; int main() { int len,k; string s; cin>>len>>k>>s; set<char> stc; for(auto i:s) stc.insert(i); for(auto ch:stc) { if(!k)break; for(string::iterator i=s.begin();i!=s.end()&&k;++i) { if(ch == *i)i=--s.erase(i),k--; } } if(s.length())cout<<s<<endl; else cout<<endl; return 0; }
C.Light It Up
原题链接:CF1000B Light It Up
题意:
有一盏在时刻亮起,同时必须在时刻熄灭的灯,给定一系列初始程序,代表在时刻,会对灯进行一次操作(灯如果是打开状态则关灯,关闭则打开),现在给你一次操作的权力(也可以不操作),问在哪个时刻进行操作,会使亮灯的时间达到最大,这个时间是多少?
分析:
动态规划,表示在第时刻没有进行任何操作的亮灯时间,代表在该时刻,插入操作或是已经插入后的亮灯时刻的最大值,因为是已经插入后的操作的最大值,因此累计的亮灯时刻应该和的相反,也就是一个遇到奇数时刻就累计亮灯的时间,一个遇到偶数时刻累计亮灯时间,最后再和不进行任何操作的时间比较一下。
代码,
#include<bits/stdc++.h> using namespace std; const int MAXN = 100007; int dp[MAXN][2]; int main() { int n,M; cin>>n>>M; vector<int> ve; ve.emplace_back(0); for(int i=1;i<=n;++i) { int input; cin>>input; ve.emplace_back(input); } ve.emplace_back(M); dp[0][0]=dp[0][1]=0; for(int i=1;i<=n+1;++i) { dp[i][0]=dp[i-1][0]; if(i&1)dp[i][0]+=ve[i]-ve[i-1]; dp[i][1]=max(dp[i-1][0]+ve[i]-ve[i-1]-1,dp[i-1][1]+((i&1)?0:ve[i]-ve[i-1])); } cout<<max(dp[n+1][1],dp[n+1][0])<<endl; // system("pause"); return 0; }
D.Convert to Ones
原题链接:CF997A Convert to Ones
题意:
有一个长度为且只含或的字符串,同时有两种操作
(1)将一段字符(字串或它本身)反转,同时需要花费的代价
(2)将一段字符(字串或它本身)中的变为,变为(即异或),同时需要花费的代价
那么把变为只含的字符串最少需要花费多少?
分析:
先分析一下两个操作:
(1)其实每进行一次反转操作,都可以把两段含有连续的子段合到一起,那么也就是说我们可以最多可以进行的反转操作的次数就是:连续的子段的个数。
(2)为了达成最少花费,每次异或操作都必须在上操作,如果我们操作的子段中有1,那么必定会有另一个含子段的异或操作会覆盖到这个,也就是说,任何对的操作都是无用功,不需要考虑。
接下来从初始状态开始分析:
如果我们不进行反转操作,那么需要花费的最小代价就是,
如果我们进行一次反转操作,那么需要花费的最小代价就是,
如果进行n次操作,最小代价就是,同时,
当我们进行次反转操作后,最小代价是,
接下来分类讨论和的情况:
当时, , ,
也就是
当时,同理可得
那么答案其实也就是
代码:
#include<bits/stdc++.h> using namespace std; int main() { int n; long long x,y; cin>>n>>x>>y; string s; cin>>s; int cnt=0; for(int i=0;i<n;++i) { int flag=1; while(s[i]=='0') { cnt+=flag; flag=0; i++; } } if(cnt)cout<<(long long)(min((cnt-1)*x+y,cnt*y))<<endl; else cout<<0<<endl; return 0; }
E.Covered Points Count
原题链接:CF1000C Covered Points Count
题意:
给个线段的起点和,问被覆盖次的点共有几个,其中。
分析:
差分。
代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 500007; long long cnt[MAXN]; inline long long read() { char ch=getchar();long long ans=0,flag=1; while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();} while(ch>='0'&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();} return ans*flag; } map<long long,long long> mp; int main() { int n=read(); for(int i=0;i<n;++i) { long long l=read(),r=read(); ++mp[l]; --mp[r+1]; } long long mark=0,fro=0; for(auto i=mp.begin();i!=mp.end();++i) { cnt[mark]+=i->first-fro; fro=i->first; mark+=i->second; } for(int i=1;i<=n;++i) cout<<cnt[i]<<" "; return 0; }