ZOJ 4054 Traveling on the Axis(思维+贡献法)

题意:

在[0,n]中每0.5处设置一个红绿灯,0表示红灯,1表示绿灯,如果在4.5处有红灯,要从4到5,就要等1s,给出初始的红绿灯状态,每1s会改变状态,即由红灯变成绿灯,或绿灯变成红灯,然后计算图中表达式。

(数轴上任意两点花费时间之和)

思路:

可以知道,如果忽略等待的时间,那么上式的值就是1*n+2*(n-1)+3*(n-2)+……+n*1。可以这样理解:从0到1,从1到2……从n-1到n都只花费1秒,有n种情况,所以从0到2,从1到3……从n-2到n就有n-1种情况,求和就可以了。这个值可以暴力算也可以推公式做,公式是(n*(n+1)*(n+2))/6。然后我们遍历一遍s,如果遇到‘0’,那么它前面的那个位置到它后面的任何位置都需要等待1秒,所以对ans的贡献就是1,再乘上位置总数(n-i)就是总贡献。如果遇到两个相同的,那么它们两个前面的任何位置到后面的任何位置都需要等待一秒,对ans的贡献也是1,再乘上位置总数(i)*(n-i)就是总贡献。i代表这个灯前面的位置数,n-1代表后面的位置数。自己动手模拟一下就懂了。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=200005;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
   /* std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);*/
    int t;
    cin>>t;
    while(t--)
    {
        string s;
        cin>>s;
        ll n=s.length();
        ll ans=0;
        for(int i=1; i<=n; i++)
        {
            ans+=(i*(n-i+1));
        }
    //    ans+=(n*(n+1)*(n+2))/6;
        for(int i=0;i<n;i++)
        {
            if(s[i]=='0')
                ans+=(n-i);
            if(i>0&&s[i]==s[i-1])
            {
                ans+=i*(n-i);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Dilly__dally/article/details/82770240
今日推荐