目录:

1.1093D. Beautiful Graph(DFS染色)

2.514C - Watto and Mechanism(Tire)

3.69E.Subsegments(STL)

4.25C. Roads in Berland(最短路松弛操作)

5.128B. String Problem (floyd预处理)

6.33C.Wonderful Randomized Sum(思维)

7.1292B.Aroma's Search (暴力+思维)

8.1286 A.Garland(DP)

9.1285D Dr. Evil Underscores (01Trie+DFS)

10.631C. Report(单调栈)

11.1119D. Frets On Fire (二分+排序)

12.1234D. Distinct Characters Queries(STL/线段树)

13.1073C. Vasya and Robot(二分+前缀和)

14.455A. Boredom(DP+map)

15.225C. Barcode(DP)

1093D. Beautiful Graph(DFS染色)

题意:

给你一个一个n个顶点,m条边的无向图,你可以将顶点赋值为1,2,3,现在问你有多少种赋值方案,使得任意一条边的两个顶点权值和为奇数

思路:

由于权值和要为奇数,所有一条边的两个顶点要一个为奇数,一个为偶数,所以就变成了一个染色问题

要注意图并不一定联通,所以答案为每个连通块内(2^(奇数)+2^(偶数))的乘积和-可以由组合数进行推导

如果有任意一个块无法染色,则答案为0

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<vector>
  4. using namespace std;
  5. typedef long long ll;
  6. const ll mod=;
  7. const int maxn=3e5+;
  8. vector<int> a[maxn];
  9. int num1,num2,color[maxn],n=,flag,two[maxn];
  10. void pre_process()
  11. {
  12. two[]=;
  13. for(int i=;i<maxn;i++)
  14. two[i]=(*two[i-])%mod;
  15. }
  16. void dfs(int x,int fa,int co)
  17. {
  18. if(!flag) return;
  19. color[x]=co;
  20. if(co==) num1++;
  21. else num2++;
  22. for(int i=;i<a[x].size();i++){
  23. int to=a[x][i];
  24. if(color[to]==color[x])
  25. {
  26. flag=;return ;
  27. }
  28. if(to!=fa&&color[to]==)
  29. {
  30. if(co==) dfs(to,x,);
  31. else dfs(to,x,);
  32. }
  33. }
  34. }
  35. int main()
  36. {
  37. int t,m,u,v;
  38. ll ans=;
  39. scanf("%d",&t);
  40. pre_process();
  41. while(t--){
  42. for(int i=;i<=n;i++) a[i].clear(),color[i]=;
  43. num1,num2,ans=;
  44. flag=;
  45. scanf("%d%d",&n,&m);
  46. for(int i=;i<=m;i++){
  47. scanf("%d%d",&u,&v);
  48. a[u].push_back(v);
  49. a[v].push_back(u);
  50. }
  51. for(int i=;i<=n;i++){
  52. if(!flag) break;
  53. if(!color[i]){
  54. num1=num2=;
  55. dfs(i,-,);
  56. ans*=(two[num1]+two[num2])%mod;
  57. ans%=mod;
  58. }
  59. }
  60. if(!flag) cout<<<<endl;
  61. else cout<<ans%mod<<endl;
  62. }
  63. return ;
  64. }

514C - Watto and Mechanism(Tire)

题意:

给n个模式串,m个匹配串,问是否有只与匹配串相差一个字符的模式串

思路:

直接上Tire,正常插入模式串

匹配时往该节点的儿子节点进行正常匹配,若能匹配成功,就输出YES

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<string>
  5. using namespace std;
  6. const int maxn=1e6+;
  7. int n,m;
  8. struct Tire{
  9. int ch[maxn][],val[maxn],cnt;
  10. void init()
  11. {
  12. cnt=;
  13. memset(ch,,sizeof(ch));
  14. val[]=;
  15. }
  16. void insert(string s){
  17. int u=,n=s.length();
  18. for(int i=;i<n;i++){
  19. int c=s[i]-'a';
  20. if(!ch[u][c]) ch[u][c]=cnt++;
  21. u=ch[u][c];
  22. }
  23. val[u]=cnt;
  24. }
  25. bool query(string s){
  26. int u=,n=s.length(),flag,k;
  27. for(int i=;i<n;i++){
  28. int c=s[i]-'a';
  29. for(int j=;j<=;j++){
  30. if(c==j||ch[u][j]==) continue;
  31. int x=ch[u][j];
  32. flag=;
  33. for(int k=i+;k<n;k++){
  34. int y=s[k]-'a';
  35. if(!ch[x][y]){
  36. flag=;
  37. break;
  38. }
  39. x=ch[x][y];
  40. }
  41. if(flag&&val[x]) return true;
  42. }
  43. if(!ch[u][c]) return false;
  44. u=ch[u][c];
  45. }
  46. return false;
  47. }
  48. }T;
  49. int main()
  50. {
  51. string temp;
  52. scanf("%d%d",&n,&m);
  53. T.init();
  54. for(int i=;i<=n;i++){
  55. cin>>temp;
  56. T.insert(temp);
  57. }
  58. for(int i=;i<=m;i++){
  59. cin>>temp;
  60. if(T.query(temp)) cout<<"YES"<<endl;
  61. else cout<<"NO"<<endl;
  62. }
  63. return ;
  64. }

69E.Subsegments(STL)

题意:

输出每一个长度为K的区间中出现次数不为1数的最大值

思路:

维护一个map与set

set用于维护当前所指向的区间(可以O(logn)直接取到最大值与删除容器内元素)

map用于维护区间内元素的出现个数

先将前k个元素加入set内,每个元素加入之后,通过map查询其出现次数,如果不为1则抹去,最后判断set是否为空,如果不为空则输出set内的最后一个元素(set容器内元素有序)

之后移动区间,需要删去一个元素这里要注意如果元素删去后其出现次数为1的话,要将其重新加入区间内

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<map>
  4. #include<set>
  5. using namespace std;
  6. const int maxn=1e5+;
  7. map<int,int> cnt;
  8. set<int> s;
  9. int a[maxn];
  10. int main()
  11. {
  12. int n,k;
  13. scanf("%d%d",&n,&k);
  14. for(int i=;i<=n;i++) scanf("%d",&a[i]);
  15. for(int i=;i<=k;i++){
  16. cnt[a[i]]++;
  17. if(cnt[a[i]]!=) s.erase(a[i]);
  18. else s.insert(a[i]);
  19. }
  20. if(s.empty()) cout<<"Nothing"<<endl;
  21. else cout<<*(--s.end())<<endl;
  22. for(int i=k+;i<=n;i++){
  23. cnt[a[i]]++;
  24. cnt[a[i-k]]--;
  25. if(cnt[a[i]]!=) s.erase(a[i]);
  26. else s.insert(a[i]);
  27. if(cnt[a[i-k]]==) s.insert(a[i-k]);
  28. else s.erase(a[i-k]);
  29. if(s.empty()) cout<<"Nothing"<<endl;
  30. else cout<<*(--s.end())<<endl;
  31. }
  32. return ;
  33. }

25C. Roads in Berland(最短路松弛操作)

题意:

给你一个dis[i][j]矩阵,代表从i顶点到j顶点的最短路,再给你k条路,每次将其加入地图中,问加入后各个顶点之间最短路的和

思路:

如果加入的道路距离比原来的距离长,则不需要修改答案

如果小于原来的距离,则先将原来的距离更新,枚举起点与重点判断能否进行松弛操作

松弛操作:dis[i][j]>dis[i][v]+w+dis[u][j]

     ②dis[i][j]>dis[i][u]+w+dis[v][j]

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. using namespace std;
  5. typedef long long ll;
  6. const int maxn=;
  7. ll dis[maxn][maxn];
  8. ll n,ans=,m,u,v,w;
  9. void solve()
  10. {
  11. for(int i=;i<=n;i++){
  12. for(int j=;j<=n;j++){
  13. if(dis[i][j]>dis[i][v]+w+dis[u][j]){
  14. ans-=dis[i][j]-(dis[i][v]+w+dis[u][j]);
  15. dis[i][j]=dis[j][i]=dis[i][v]+w+dis[u][j];
  16. }
  17. if(dis[i][j]>dis[i][u]+w+dis[v][j]){
  18. ans-=dis[i][j]-(dis[i][u]+w+dis[v][j]);
  19. dis[i][j]=dis[j][i]=dis[i][u]+w+dis[v][j];
  20. }
  21. }
  22. }
  23. }
  24. int main()
  25. {
  26. scanf("%lld",&n);
  27. for(int i=;i<=n;i++)
  28. for(int j=;j<=n;j++){
  29. scanf("%lld",&dis[i][j]);
  30. ans+=dis[i][j];
  31. }
  32. ans/=;
  33. scanf("%lld",&m);
  34. for(int i=;i<=m;i++){
  35. scanf("%lld%lld%lld",&u,&v,&w);
  36. if(dis[u][v]<=w){
  37. cout<<ans<<" ";
  38. continue;
  39. }
  40. else{
  41. ans-=dis[u][v]-w;
  42. dis[u][v]=dis[v][u]=w;
  43. solve();
  44. cout<<ans<<" ";
  45. }
  46. }
  47. return ;
  48. }

128B. String Problem (floyd预处理)

题意:

给两个字符串,以及m个从字符a变换到b的代价,问把两个字符串变得相同的最小代价

思路:

将字符串变换的代价当做一条有向边建图,之后跑floyd,得到从字符i变成j的最小代价dis[i][j]

之后遍历两个字符串的每一位,不相同的话枚举变成什么字符所需要的代价最小,如果找不到这样一个中间点使得s1[i]=ch,s2[i]=ch,则直接输出-1,最后将最小代价累加就好了

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #define inf 0x3f3f3f3f
  5. using namespace std;
  6. const int maxn=1e5+;
  7. int dis[][],mp[][];
  8. char s1[maxn],s2[maxn],a1,a2,s3[maxn];
  9. void floyd()
  10. {
  11. for(int i=;i<;i++)
  12. for(int j=;j<;j++) dis[i][j]=mp[i][j];
  13. for(int k=;k<;k++)
  14. for(int i=;i<;i++)
  15. for(int j=;j<;j++)
  16. dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
  17. }
  18. int main()
  19. {
  20. int n,w;
  21. cin>>s1>>s2>>n;
  22. for(int i=;i<;i++)
  23. for(int j=;j<;j++){
  24. if(i==j) mp[i][j]=;
  25. else mp[i][j]=inf;
  26. }
  27. for(int i=;i<=n;i++){
  28. cin>>a1>>a2>>w;
  29. int u=a1-'a',v=a2-'a';
  30. mp[u][v]=min(mp[u][v],w);
  31. }
  32. floyd();
  33. int len1=strlen(s1),len2=strlen(s2);
  34. if(len1!=len2){
  35. cout<<-<<endl;
  36. return ;
  37. }
  38. int ans=;
  39. for(int i=;i<len1;i++){
  40. if(s1[i]==s2[i]){s3[i]=s1[i];continue;}
  41. else{
  42. int mini=inf,x=-,u=s1[i]-'a',v=s2[i]-'a';
  43. for(int j=;j<;j++){
  44. if(dis[u][j]+dis[v][j]<mini) mini=dis[u][j]+dis[v][j],x=j;
  45. }
  46. if(x==-){
  47. cout<<"-1"<<endl;
  48. return ;
  49. }
  50. else{
  51. s3[i]=x+'a';
  52. ans+=mini;
  53. }
  54. }
  55. }
  56. cout<<ans<<endl<<s3<<endl;
  57. return ;
  58. }

 33C.Wonderful Randomized Sum

题意:

给一个数组你可以把一段前缀和乘上-1,再把一个后缀和乘上-1,前缀跟后缀之间可以有重叠部分,问操作后序列的最大和是多少

思路:

我们先考虑有重叠的部分,由于乘了两次-1,所有重合的部分不变,因此答案的方案肯定不会有重叠部分

我们假设所有元素的和为sum,从反面思考假设中间的那段和为s,那么操作后数组的和为-(sum - s) + s = 2 * s - sum

所以问题就转化为找一个最大子序列问题了

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int maxn=1e5+;
  5. int a[maxn];
  6. int main()
  7. {
  8. int n,sum=;
  9. scanf("%d",&n);
  10. for(int i=;i<=n;i++){
  11. scanf("%d",&a[i]);
  12. sum+=a[i];
  13. }
  14. int mx,cnt=;
  15. for(int i=;i<=n;i++){
  16. cnt+=a[i];
  17. if(cnt<) cnt=;
  18. mx=max(mx,cnt);
  19. }
  20. cout<<*mx-sum<<endl;
  21. return ;
  22. }

 1292B.Aroma's Search (暴力+思维)

题意:

告诉一个点的位置,之后的点按照x[i]=x[i-1]*ax+bx;,y[i]=y[i-1]*ay+by的规律分布,初始时你站在一个位置,每秒可以往四个方向移动,问你在t内最多能走过多少个点

思路:

通过数据我们可以发现,在264就已经超过了1e16也就是t的范围了,因此地图内最多只有64个点

所以我们只需要暴力求出每一个点的坐标,再枚举你所走的点的起点与终点(只往一个方向走连续的点肯定是最优)

判断距离(从初始位置走到起点的距离再加上起点到终点的距离)是否小于t即可,求出一个最大值就是答案啊

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cmath>
  4. using namespace std;
  5. typedef long long ll;
  6. ll x[],y[];
  7. ll dis(ll x1,ll y1,ll x2,ll y2)
  8. {
  9. return abs(x1-x2)+abs(y1-y2);
  10. }
  11. int main()
  12. {
  13. ll ax,ay,bx,by,xs,ys,t;
  14. int cnt=;
  15. cin>>x[]>>y[]>>ax>>ay>>bx>>by;
  16. cin>>xs>>ys>>t;
  17. while(x[cnt]-xs<t&&y[cnt]-ys<t){
  18. cnt++;
  19. x[cnt]=x[cnt-]*ax+bx;
  20. y[cnt]=y[cnt-]*ay+by;
  21. }
  22. int ans=;
  23. for(int i=;i<=cnt;i++){
  24. for(int j=i;j<=cnt;j++){
  25. if(j-i+<=ans) continue;
  26. ll temp=min(dis(x[i],y[i],xs,ys),dis(x[j],y[j],xs,ys));
  27. temp+=dis(x[i],y[i],x[j],y[j]);
  28. if(temp<=t) ans=j-i+;
  29. }
  30. }
  31. cout<<ans<<endl;
  32. return ;
  33. }

1286 A.Garland(DP)

题意:

有一个数组,包含乱序1-n的元素,并且有些数被从数组中拿出,现在问怎样将这些数放回才能使,相邻两数为奇偶的对数最小

思路:

定义dp[i][j][k]为到n这个位置放了j个偶数最后一位为奇数或偶数

那么转移方程为:

令t=dp[i-1][j][k]

i.奇数:dp[i][j][1]=max(dp[i][j][1],t+(k!=1))

ii.偶数:dp[i][j+1][0]=max(dp[i][j][0],t+(k!=0))

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #define inf 0x3f3f3f3f
  5. using namespace std;
  6. const int maxn=;
  7. int dp[maxn][maxn][],a[maxn],n;
  8. int main()
  9. {
  10. int n,num=;
  11. scanf("%d",&n);
  12. for(int i=;i<=n;i++) scanf("%d",&a[i]);
  13. num=n/;
  14. memset(dp,inf,sizeof(dp));
  15. dp[][][]=dp[][][]=;
  16. for(int i=;i<=n;i++){
  17. for(int j=;j<i;j++){
  18. for(int k=;k<;k++){
  19. int t=dp[i-][j][k];
  20. if(a[i]){
  21. if(a[i]%) dp[i][j][]=min(dp[i][j][],t+(k!=));
  22. else dp[i][j+][]=min(dp[i][j+][],t+(k!=));
  23. }
  24. else{
  25. for(int l=;l<;l++)
  26. dp[i][j+-l][l]=min(dp[i][j+-l][l],t+(l!=k));
  27. }
  28. }
  29. }
  30. }
  31. printf("%d\n", min(dp[n][num][], dp[n][num][]));
  32. }

1285D Dr. Evil Underscores (01Trie+DFS)

题意:

给一个数组a,现在让你找到一个x使得max(x^ai)最小

思路:

建立起一颗Tire,对Tire进行DFS

如果对于当前位,即有0又有1,则对左右两个子树分别DFS并取最小值

当前位没有值的话,直接返回0

如果只有0或者1,那就对相应子树进行DFS

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. typedef long long ll;
  5. const int maxn=2e6+;
  6. struct Tire{
  7. int cnt,ch[maxn][];
  8. void insert(int x)
  9. {
  10. int u=;
  11. for(int i=;i>=;i--){
  12. bool v=(<<i)&x;
  13. if(!ch[u][v]){
  14. ch[u][v]=++cnt;
  15. }
  16. u=ch[u][v];
  17. }
  18. }
  19. int dfs(int x,int dep)
  20. {
  21. int k1=ch[x][],k2=ch[x][];
  22. if(!k1&&!k2)
  23. return ;
  24. if(k1&&!k2)
  25. return dfs(k1,dep-);
  26. if(k2&&!k1)
  27. return dfs(k2,dep-);
  28. return (<<dep)+min(dfs(k1,dep-),dfs(k2,dep-));
  29. }
  30.  
  31. }T;
  32. int main()
  33. {
  34. int n,temp;
  35. scanf("%d",&n);
  36. for(int i=;i<=n;i++){
  37. scanf("%d",&temp);
  38. T.insert(temp);
  39. }
  40. cout<<T.dfs(,)<<endl;
  41. }

631C. Report(单调栈)

题意:

给你一个数组,并且进行若干次操作,每次操作可以将1-R,升序或者降序排列,求出经过若干次操作后的数组

思路:

对于一些操作,比如i < j并且R< Rj那么i操作是没有意义的,因此我们可以建立一个单调栈,将操作次数进行缩减,并得到一个以R降序的操作序列,最大的操作区间长度为len

现在将a数组的前len个元素复制到b数组,并且排序

之后从右向左向a数组中按照每次操作的排序方式填数即可

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. using namespace std;
  5. const int maxn=2e5+;
  6. int a[maxn],b[maxn];
  7. struct query{
  8. int t,r;
  9. }c[maxn];
  10. int main()
  11. {
  12. int n,m,s=,t,r,l;
  13. scanf("%d%d",&n,&m);
  14. for(int i=;i<n;i++) scanf("%d",&a[i]);
  15. for(int i=;i<=m;i++){
  16. scanf("%d%d",&t,&r);
  17. while(s>&&r>=c[s-].r) s--;
  18. c[s].t=t,c[s].r=r,s++;
  19. }
  20. l=,r=c[].r,c[s].r=,s++;
  21. for(int i=;i<r;i++) b[i]=a[i];
  22. sort(b,b+r);
  23. for(int i=;i<s;i++)
  24. for(int j=c[i-].r;j>c[i].r;j--)
  25. a[j-]=(c[i-].t==)?b[--r]:b[l++];
  26. for(int i=;i<n;i++) cout<<a[i]<<" ";
  27. return ;
  28. }

1119D. Frets On Fire (二分+排序)

题意:

给n个数Ai,那么矩阵Ci,j = Ai + j(j≤1e18),现在给q个询问,每次询问这个矩阵l列到j列有多少个不同的元素

思路:

首先对a数组排序去重,显然这对答案不会有影响

对于排序去重之后数组中的两个相邻元素,如果他们之间的差值大于r-l+1,那么更小的那行对答案的贡献就为r-l+1,否则就为差值

因此我们求出一差分数组,并在此排序,求出前缀和sum数组

对于每次询问,我们用二分在差分数组中找到最后一个小于r-l+1的位置pos,那么本次查询的答案就为sun[pos] + (len-pos+1)*(r-l+1)

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. typedef long long ll;
  5. const int maxn=1e5+;
  6. ll a[maxn],b[maxn],sum[maxn],l,r,ans[maxn];
  7. int n,q;
  8. int main()
  9. {
  10. scanf("%d",&n);
  11. for(int i=;i<=n;i++) scanf("%lld",&a[i]);
  12. sort(a+,a++n);
  13. int len=unique(a+,a++n)-a-;
  14. for(int i=;i<len;i++) b[i]=a[i+]-a[i];
  15. sort(b+,b+len);
  16. for(int i=;i<len;i++) sum[i]=sum[i-]+b[i];
  17. scanf("%d",&q);
  18. for(int i=;i<=q;i++){
  19. scanf("%lld%lld",&l,&r);
  20. int li=,ri=len-;
  21. ll ret=r-l+;
  22. while(li<=ri){
  23. int mid=(li+ri)>>;
  24. if(b[mid]<=r-l+) li=mid+;
  25. else ri=mid-;
  26. }
  27. li--;
  28. ret+=(sum[li]+(len-li-)*(r-l+));
  29. cout<<ret<<" ";
  30. }
  31. }

1234D. Distinct Characters Queries(STL/线段树)

题意:

给一个字符串,两种操作:1.进行单点修改2.询问区间l-r有多少个不同的字母

思路:

方法一:建立26棵线段树

方法二:建立26个set,每个set存相应字母出现的位置

    对于修改,先在原来的字母对应的set中删除位置,再在更新的字母对应的set中插入位置

    由于set中元素都为有序的,所以每次询问,在每个set中进行二分找l如果找到的元素小于等于r答案就加一

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<set>
  4. using namespace std;
  5. set<int> a[];
  6. string temp;
  7. int main()
  8. {
  9. cin>>temp;
  10. int n,op,pos,l,r;
  11. char ch;
  12. for(int i=;i<temp.size();i++) a[temp[i]-'a'].insert(i+);
  13. scanf("%d",&n);
  14. while(n--){
  15. scanf("%d",&op);
  16. if(op==){
  17. cin>>pos>>ch;
  18. a[temp[pos-]-'a'].erase(pos);
  19. temp[pos-]=ch;
  20. a[temp[pos-]-'a'].insert(pos);
  21. }
  22. else{
  23. cin>>l>>r;
  24. int num=;
  25. for(int i=;i<;i++){
  26. set<int>::iterator it;
  27. it=a[i].lower_bound(l);
  28. if(it!=a[i].end()&&*it<=r) num++;
  29. }
  30. cout<<num<<endl;
  31. }
  32. }
  33. return ;
  34. }

 1073C. Vasya and Robot(二分+前缀和)

题意:

给你一串移动指令,与一个目的地,你可以对指令进行修改,每次修改的花费为,最右边的修改位置减去最左边的修改位置+1,让你求最少花费

思路:

二分答案进行判断,如何判断呢?

先用前缀和记录下每段指令中每个方向移动的次数

每次只需要判断x-(abs(ex-cntx)+abs(ey-cnty))是否为2的倍数即可,因为多出来的部分可以走相反的方向进行抵消,所以判断是否为2的倍数

其中cntx为为改变区域中在x方向上的移动距离,以x轴正方向为正,cnty类似

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<map>
  4. #include<cmath>
  5. using namespace std;
  6. const int maxn=2e5+;
  7. map<char,int> m;
  8. int sum[][maxn],ex,ey,n;
  9. string s;
  10. int judge(int x)
  11. {
  12. int l,r,u,d,cntx,cnty;
  13. if(x==n){
  14. int temp=x-abs(ex)-abs(ey);
  15. if(temp>=&&temp%==)
  16. return ;
  17. return ;
  18. }
  19. for(int i=;i<=n-x+;i++){
  20. l=sum[][i-]+(sum[][n]-sum[][i+x-]);
  21. r=sum[][i-]+(sum[][n]-sum[][i+x-]);
  22. u=sum[][i-]+(sum[][n]-sum[][i+x-]);
  23. d=sum[][i-]+(sum[][n]-sum[][i+x-]);
  24. cnty=u-d,cntx=r-l;
  25. int temp=x-(abs(ey-cnty)+abs(ex-cntx));
  26. if(temp>=&&temp%==) return ;
  27. }
  28. return ;
  29. }
  30. int main()
  31. {
  32. scanf("%d",&n);
  33. cin>>s>>ex>>ey;
  34. int ret=-,l=,r=n;
  35. m['L']=,m['R']=,m['U']=,m['D']=;
  36. for(int i=;i<=n;i++){
  37. for(int j=;j<;j++)
  38. sum[j][i]=sum[j][i-];
  39. sum[m[s[i-]]][i]++;
  40. }
  41. while(l<=r){
  42. int mid=(l+r)>>;
  43. if(judge(mid)) r=(ret=mid)-;
  44. else l=mid+;
  45. }
  46. cout<<ret<<endl;
  47. }

455A. Boredom(DP+map)

题意:

给一个数组,每次可以从数组中拿出一个数,但是每拿一次就得将所有x+1,x-1的数从数组中删除,问你能拿出数的最大和是多少

思路:

拿map记录下每个数出现的次数,然后对数组排序去重,之后开始DP

DP为选了第i个数的最大值

转移方程式为:dp[i]=max(dp[i],dp[i-1]+a[i]*s[a[i]]) (a[i]>a[i-1]+1)

       dp[i]=max(dp[i],mx+a[i]*s[a[i]]) (mx为dp[1]-dp[i-2]中的最大值)

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<map>
  5. using namespace std;
  6. typedef long long ll;
  7. const int maxn=1e5+;
  8. map<ll,int> s;
  9. ll a[maxn],dp[maxn];
  10. int main()
  11. {
  12. int n;
  13. scanf("%d",&n);
  14. for(int i=;i<=n;i++){
  15. scanf("%lld",&a[i]);
  16. s[a[i]]++;
  17. }
  18. sort(a+,a++n);
  19. int len=unique(a+,a++n)-a-;
  20. dp[]=a[]*s[a[]];
  21. ll ans=dp[],mx=;
  22. for(int i=;i<=len;i++){
  23. if(a[i]>a[i-]+) dp[i]=max(dp[i],dp[i-]+a[i]*s[a[i]]);
  24. dp[i]=max(dp[i],mx+a[i]*s[a[i]]);
  25. mx=max(dp[i-],mx);
  26. ans=max(ans,dp[i]);
  27. }
  28. cout<<ans<<endl;
  29. return ;
  30. }

225C. Barcode(DP)

题意:

有一个矩阵,每个位置是#或.,现你可以改变矩阵中某些位置,使得矩阵满足每列都相同,同一种符号的列连续出现的次数cnr必须满足,x≤cnt≤y

思路:

先求出把1-i列全部变成#的前缀和,然后定义dp[i][j]为前1-i列,最后连续一段为j所需要的最小花费

那么状态转移方程式为:f[i][0]=min(f[i][0],f[i-j][1]+(s[i]-s[i-j]))

           f[i][1]=min(f[i][1],f[i-j][0]+n*j-(s[i]-s[i-j]))

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. int a[][];
  5. int s[];
  6. char c[];
  7. int f[][];
  8. int main(){
  9. memset(f,,sizeof(f));
  10. f[][]=f[][]=;
  11. int n,m,x,y;
  12. scanf("%d%d%d%d",&n,&m,&x,&y);
  13. for(int i=;i<=n;i++){
  14. scanf("%s",c+);
  15. for(int j=;j<=m;j++){
  16. a[i][j]=(c[j]=='#'?:);
  17. }
  18. }
  19. for(int i=;i<=m;i++){
  20. for(int j=;j<=n;j++){
  21. s[i]+=a[j][i];
  22. }
  23. s[i]+=s[i-];
  24. }
  25. for(int i=x;i<=m;i++){
  26. for(int j=x;j<=y;j++){
  27. if(i-j>=){
  28. f[i][]=min(f[i][],f[i-j][]+(s[i]-s[i-j]));
  29. f[i][]=min(f[i][],f[i-j][]+n*j-(s[i]-s[i-j]));
  30. }
  31. }
  32. }
  33. printf("%d\n", min(f[m][],f[m][]));
  34. return ;
  35. }

codeforces每日一题1-10的更多相关文章

  1. <每日一题>题目10:求斐波拉契数列

    def func(x): m,n = 0,1 i = 0 while i < x: yield m m,n = n,m+n i += 1 fib = [] get_func = func(100 ...

  2. CISP/CISA 每日一题 10

    CISA 每日一题(答)一个合理建造的数据仓库应当支持下列三种基本的查询格式: 1.向上溯源和向下溯源——向上溯源是对数据进行总计:向下溯源是将数据进行细化: 2.交叉溯源——通过通用属性访问数据仓库 ...

  3. 【Java每日一题】20161214

    package Dec2016; import java.util.ArrayList; import java.util.List; public class Ques1214 { public s ...

  4. 【Java每日一题】20161212

    package Dec2016; public class Ques1212 { public static void main(String[] args){ System.out.println( ...

  5. 【Java每日一题】20161020

    20161019问题解析请点击今日问题下方的"[Java每日一题]20161020"查看 package Oct2016; public class Ques1020 { publ ...

  6. 【Java每日一题】20170112

    20170111问题解析请点击今日问题下方的"[Java每日一题]20170112"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  7. 【Java每日一题】20170327

    20170324问题解析请点击今日问题下方的“[Java每日一题]20170327”查看(问题解析在公众号首发,公众号ID:weknow619) package Mar2017; public cla ...

  8. 【Java每日一题】20170217

    20170216问题解析请点击今日问题下方的“[Java每日一题]20170217”查看(问题解析在公众号首发,公众号ID:weknow619) package Feb2017; public cla ...

  9. 【Java每日一题】20170213

    20170210问题解析请点击今日问题下方的“[Java每日一题]20170213”查看(问题解析在公众号首发,公众号ID:weknow619) package Feb2017; public cla ...

随机推荐

  1. vue hash模式下微信分享后打开首页,三种完美解决方案

    微信分享功能给我们带来了很大的便利,使得基于微信开发出来的 H5 页面可以很好的通过微信平台进行传播.所以呢,基本上每个基于微信开发的 H5 都会集成微信分享功能.但是,前几天在对接微信分享 API ...

  2. Webpack 中 file-loader 和 url-loader 的区别

    如果我们希望在页面引入图片(包括img的src和background的url).当我们基于webpack进行开发时,引入图片会遇到一些问题. 其中一个就是引用路径的问题.拿background样式用u ...

  3. Solr系列4-SolrJ开发应用

    1: Solr导入 1.1导入POM # Base Code Java org.apache.solr solr-solrj 8.4.0 # spring boot org.springframewo ...

  4. Android埋点方案的简单实现-AOP之AspectJ

    个人博客 http://www.milovetingting.cn Android埋点方案的简单实现-AOP之AspectJ AOP的定义 AOP为Aspect Oriented Programmin ...

  5. if 语句 总结笔记

    1.if 语句 语法: if(condition) statement1; else statement2; graph TD A[JAVA考试] -->|几天后| B(收到成绩单) B --& ...

  6. BigDecimal精确计算工具类

    前言 在实际开发中,遇到例如货币,统计等商业计算的时候,一般需要采用java.math.BigDecimal类来进行精确计算.而这类操作通常都是可预知的,也就是通用的.所以,写了个工具类来方便以后的工 ...

  7. CommonJs模块化(nodejs模块规范)

    1.概述: Node应用由模块组成,采用CommonJS模块规范. 根据这个规范,每个文件就是一个模块,有自己的作用域.在一个文件里面定义的变量.函数.类,都是私有的,对其他文件不可见. 如果想在多个 ...

  8. 安装Nexus到Linux(源码)

    运行环境 系统版本:CentOS Linux release 7.4.1708 (Core) 软件版本:Sonatype-Nexus-3.14.0 硬件要求:无 安装过程 1. 调整系统参数 需要调整 ...

  9. 【Spring】bean的作用域(@Scope) - singleton、prototype

    已知spring 3+已拥有多种不同的作用域: singleton(默认).prototype.request.session.global session.(参考: spring中scope作用域( ...

  10. C语言 杂货整理

    C语言 杂货整理 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include ...