CodeForces - 1027(div2)

版权声明:转载请告知博主并要注明出处嗷~ https://blog.csdn.net/Akatsuki__Itachi/article/details/81975463

A. Palindromic Twist

题意:每个字母都会变成它的ASCII值+1或者-1的情况(不可能不变化),问有没有一种可能的变化使得最后的串为回文串?

思路:从中间向两边遍历+判断

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
#define memset(a,v)  memset(a,v,sizeof(a))
using namespace std;
const int MAXL(3*1e5);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
string str;
bool judge(int i,int j)
{
    if(str[i]-1==str[j]-1)
        return true;
    if(str[i]-1==str[j]+1)
        return true;
    if(str[i]+1==str[j]-1)
        return true;
    if(str[i]+1==str[j]+1)
        return true;
    return false;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        cin>>str;
        int flag=0;
        for(int i=n/2,j=n/2-1;i<n;i++,j--)
        {
            if(judge(i, j)==false)
            {
                flag=1;
                break;
            }
        }
        if(flag)
            cout<<"NO"<<endl;
        else
            cout<<"YES"<<endl;
    }
}

B. Numbers on the Chessboard

题意:有一个n*n大小的方格,里面有n^2个数字,数字是按照这样的规则安防的:从1开始,下标从(1,1)开始。当下标的和为偶数的时候从左向右吗,从上到校按序依次放置数字,然后放置下标和为奇数的方格。给出q个询问,问下标为(x,y)的方格的数字是多少?

思路:直接找规律就好,我写的代码可能会有点冗杂。

n分奇偶的情况。

1.当n为偶数时:

①下标和为偶数时:因为数字是按照顺序依次递增的,所以我们先统计出第1到x-1行有多少个数字,然后再加上第x行有多少个数字,最后相加即可。

②下标和为奇数时:①得出的答案+n*n / 2

2.当n为奇数时:

这个情况稍微复杂些.

因为每两行的数字会差了一个,所以我们把两行看成一行去计算,然后按照上面的方法找出和。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
#define memset(a,v)  memset(a,v,sizeof(a))
using namespace std;
const int MAXL(3*1e5);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
int main()
{
    LL n,q;
    cin>>n>>q;
    while(q--)
    {
        LL x,y;
        cin>>x>>y;
        if( !(n&1) )//n为偶数
        {
            if((x+y)&1)//下标和为奇数的情况
            {
                LL temp=n/2;
                LL sum=temp*(x-1); //这个是统计每行上面有多少个数字
                if(y&1)
                    y=(y+1)/2;
                else
                    y/=2; //if else 统计当前行有多少个数字
                cout<<n*n/2+sum+y<<endl;//前面还要加上n^2 / 2
            }
            else
            {
                LL temp=n/2;
                LL sum=temp*(x-1);
                if(y&1)
                    y=(y+1)/2;
                else
                    y/=2;
                cout<<sum+y<<endl;
            }
        }
        else
        {
            if((x+y)&1)
            {
                LL temp=n/2;
                LL sum=0;
                if(x&1)
                    sum=(x-1)/2*n+y/2;
                else
                    sum=(x-2)/2*n+temp+(y+1)/2;
                cout<<n*n/2+1+sum<<endl;
            }
            else
            {
                LL temp=n/2+1;
                LL sum=0;
                if(x&1)
                    sum=(x-1)/2*n+(y+1)/2;
                else
                    sum=(x-2)/2*n+temp+y/2;
                cout<<sum<<endl;
            }
        }
    }
}

C. Minimum Value Rectangle

题意:给出n个数字,n>=4。从这里面选出4个组成一个长方形,使得周长的平方/面积 最小。

输入保证答案存在。

思路:假设选出来的长为 L,高位H。那么周长的平方C^2=4*(L+H)^2,面积S=LH。

4为常数,不影响最终结果,扔掉~

那么C^2/S 可以最后化简为 L/H + H/L 的形式。

由上式可知,当L==H的时候,答案最小。

如果没有L==H的情况,那么我们就把所有可能组成的边比较,找出最小的答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define memset(a,v)  memset(a,v,sizeof(a))
#define eps 1.0E-8
using namespace std;
const int MAXL(1e4);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
int haxi[MAXL+50];
int a[1000000+50];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        memset(haxi,0);
        int len=0;
        int flag=0;
        int temp=0,ans1=0,ans2=0;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            haxi[x]++;
            if(haxi[x]==2)
                a[len++]=x;
            if(haxi[x]==4)//正方形的情况,直接得到答案
            {
                flag=1;
                ans1=ans2=x;
            }
        }
        if(!flag)
        {
            double mi=INF;
            sort(a,a+len);
            for(int i=1;i<len;i++)
            {
                double x=1.0*a[i-1]/a[i];
                double y=1.0*a[i]/a[i-1];
                if(x+y<mi)
                {
                    mi=x+y;
                    ans1=a[i-1];
                    ans2=a[i];
                }
            }
        }
        cout<<ans1<<" "<<ans1<<" "<<ans2<<" "<<ans2<<endl;
    }
}

D. Mouse Hunt

题意:有n个房间,一只老鼠,现在我们要抓住这只老鼠,于是我们要在房间里设置老鼠夹。可是我们想用最少的花费并同时保证一定可以抓住老鼠。

所以输入的第一行为在每个房间里设置老鼠夹所需要的花费。

老鼠如何行动呢?它可能会从任意一个房间里出来,并且可能会跑到任何一个房间。

所以输入的第二行为在第 i 个房间时,这只老鼠会跑到第a[i]个房间。

PS:如果 i==a[i] ,那么老鼠这时候就不跑了。


思路:一开始可能会想到并查集,但是我写的并查集没有A掉...可能是因为在设置祖先的时候情况分的不对。

后来把输入的第二行画成一个图时,思路就变的开始清晰起来。

①首先老鼠在每个房间一定会跑到下一个房间,只有当 i==a[i]时,才终止跑路。

所以我们必须要在这样的房间内设置一个老鼠夹,不管他从哪个房间来,一定会在这里抓住。

②但是还是有别的情况,比如老鼠从2跑到房间3,3又跑到房间2,形成了一个环。

这时候我们就需要在这个环里面的所有房间,找一个花费最小的房间设置老鼠夹。

一定会有环吗?

一定会有环。

因为老鼠每次都要跑到下一个房间,所以一定会再次跑回之前跑过的房间。

有一种情况:

从1->2>3>4->5,

最后5的a[5]为5,也可以看做5这个点为一个环。

算法:输入的时候把①的情况先处理掉,然后对剩下的图拓扑排序,把入度为0的点处理掉,最后剩下一个环,在环里找最小的花费即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define memset(a,v)  memset(a,v,sizeof(a))
#define eps 1.0E-8
using namespace std;
const int MAXL(2*1e5);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
int a[MAXL+50];
int c[MAXL+50];
int indegree[MAXL+50];
int vis[MAXL+50];
int n;
LL ans=0;
void toposort()
{
    queue<int>q;
    for(int i=1;i<=n;i++)
        if(!vis[i] && !indegree[i]) q.push(i),vis[i]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        indegree[a[u]]--;
        vis[u]=1;
        if(!indegree[a[u]]&&!vis[a[u]])
            q.push(a[u]);
    }
}
void solve()
{
    for(int i=1;i<=n;i++)
    {
        if(vis[i]) continue;
        int u=i,v=a[u];
        vis[u]=vis[v]=1;
        int temp=c[u];
        while(u!=v)
        {
            temp=min(temp,c[v]);
            v=a[v];
            vis[v]=1;
        }
        ans+=temp;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",c+i);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",a+i);
        if(a[i]==i)
            ans+=c[i],vis[i]=1;
        else
            indegree[a[i]]++;
    }
    toposort();
    solve();
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/Akatsuki__Itachi/article/details/81975463