poj 3276(反转)

传送门:Problem 3276

参考资料:

  [1]:挑战程序设计竞赛

先献上AC代码,题解晚上再补

题意:

  John有N头牛,这些牛有的头朝前("F"),有的朝后("B"),John想让所有的牛头都超前。

  现在,John得到了一个机器,每次可以让连续的 K 头牛转向,问最少需要用多少次(M)机器可以使所有的牛头都超前?

题解:

  变量解释:

    dir[i] : dir[i]=0 -> 第i头牛面朝前;dir[i]=1 -> 第i头牛面朝后

    f[i] : f[i]=0 -> 在第i头牛出不进行反转操作;f[i]=1 -> 在第i头牛出进行反转操作

  首先,需要明白两点:

    (1):交换区间反转的顺序对结果是没有影响的。

    (2):对同一个区间进行两次以上的反转是多余的。

  因此,问题就转化成了求需要被反转的区间的集合。

  定义 k : 每次需要反转的牛的个数(1 <= k <= N)

     i : 第 i 头牛(1 <= i <= N-k+1,初始 i =  1)

    sum : 受前面反转影响([i-k+1,i-1]),来到第 i 头牛,总共反转的次数

    res : 存储反转次数

  (1):对于第i头来说,如果它是面朝后的,则需要一次反转使其面朝前,而之后的反转区间指定不包含此牛。

  (2):判断第i头牛是否需要反转,如果需要,f[i]=1,res++;i++;

  (3):重复(2)过程,直到 i > N-k+1为止

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int maxn=5e3+50;
 5 
 6 int N;
 7 int dir[maxn];
 8 int f[maxn];
 9 
10 int Calculate(int k)
11 {
12     int res=0;
13     int sum=0;
14     for(int i=1;i <= N-k+1;++i)
15     {
16         if(i-k > 0)//当前的i只受到区间 [i-k+1,i-1] 反转的影响,所以需要去除i-k对i的反转影响
17             sum -= f[i-k];
18         if((dir[i]+sum)%2 != 0)//判断dir[i] 是否为偶数,偶数代表面朝前
19             f[i]=1,res++;
20         sum += f[i];
21     }
22     for(int i=N-k+2;i <= N;++i)//检查后 k-1头牛是否全都面朝前
23     {
24         if(i-k > 0)//解释同上
25             sum -= f[i-k];
26         if((dir[i]+sum)%2 != 0)
27             return -1;
28     }
29     return res;
30 }
31 void Solve()
32 {
33     int K=1,M=N;
34     for(int k=1;k <= N;++k)//每次反转 k 头牛
35     {
36         int m=Calculate(k);
37         if(m != -1 && m < N)
38             K=k,M=m;
39     }
40     printf("%d %d\n",K,M);
41 }
42 
43 int main()
44 {
45     scanf("%d",&N);
46     for(int i=1;i <= N;++i)
47     {
48         getchar();
49         char ch=getchar();
50         dir[i]=(ch == 'F' ? 0:1);
51     }
52     Solve();
53 }
View Code

 

转载于:https://www.cnblogs.com/violet-acmer/p/9802218.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值