Codeforces Round #601 (Div. 2) / contest 1255

目录

        • A Changing Volume
        • B Fridge Lockers
        • C League of Leesins
        • D Feeding Chicken
        • E Send Boxes to Alice (Hard Version)
        • F Point Ordering


题目地址:https://codeforces.com/contest/1255



A Changing Volume

题意

思路:简单贪心策略即可。

代码

int main()
{
    //freopen("input.txt","r",stdin);
    int T=read();
    while(T--)
    {
        int a=read(),b=read(),ans=0;
        if(a>b) swap(a,b);
        ans+=(b-a)/5; a+=ans*5;
        ans+=(b-a)/2; a+=(b-a)/2*2;
        ans+=(b-a);
        printf("%d\n",ans);
    }

    return 0;
}



B Fridge Lockers

题意

思路:根据题意每个冰箱至少要连接两条边,也就是说每个结点的权值至少要贡献两次,而每个结点只要贡献两次就可以符合题意,所以只要在m==n的情况下输出一个环就可以了。

代码

const int maxn=1005;
int n,m,a[maxn];

int main()
{
    //freopen("input.txt","r",stdin);
    int T=read();
    while(T--)
    {
        n=read(),m=read();
        REP(i,1,n) a[i]=read();
        if(n<=2 || m<n) puts("-1");
        else
        {
            int ans=0;
            REP(i,1,n-1) ans+=a[i]+a[i+1];
            ans+=a[1]+a[n];
            printf("%d\n",ans);
            REP(i,1,n-1) printf("%d %d\n",i,i+1);
            printf("1 %d\n",n);
        }
    }

    return 0;
}



C League of Leesins

题意

思路:通过出现次数可以确定第一个数(二选一),然后因为相邻两个三元组有两个数是一样的,因此可以确定唯一的下一个三元组,也可以确定唯一的下一个数(最终答案应该有两种)

代码

const int maxn=1e5+5;
int times[maxn],a[maxn][3],n;
set<int> s[maxn];

int main()
{
    //freopen("input.txt","r",stdin);
    n=read();
    REP(i,1,n-2) REP(j,0,2) a[i][j]=read(),times[a[i][j]]++,s[a[i][j]].insert(i);
    int k=0,where=0,tempa,tempb;
    REP(i,1,n) if(times[i]==1) {k=i; break;}
    REP(i,1,n-2)
    {
        int flag=0;
        REP(j,0,2) if(a[i][j]==k) {flag=1; break;}
        if(flag) {where=i; break;}
    }
    printf("%d ",k);
    REP(j,0,2) if(times[a[where][j]]==2) tempa=a[where][j];
    REP(j,0,2) if(times[a[where][j]]==3) tempb=a[where][j];
    printf("%d %d ",tempa,tempb);

    REP(i,4,n)
    {
        #define iter(s) s.begin(),s.end()
        vector<int> t(2);
        set_intersection(iter(s[tempa]),iter(s[tempb]),t.begin());
        where=t[0]==where?t[1]:t[0];
        int temp;
        REP(j,0,2) if(a[where][j]!=tempa && a[where][j]!=tempb) temp=a[where][j];
        printf("%d ",temp);
        tempa=tempb; tempb=temp;
    }

    return 0;
}



D Feeding Chicken

题意:一个二维的矩形农场,有一些格子有食物,有k只鸡,给每只鸡分配一个联通的区域,使得食物数目尽可能平分。

思路:将二维数组化为一个连续的一维数组,那么只要分配一段连续的区间,就可以保证在二维联通,然后平均分配即可。

代码

const int maxn=105;
int a[maxn][maxn],x[maxn*maxn],y[maxn*maxn],b[maxn*maxn];
int r,c,k,n,t[maxn],tot,ans[maxn][maxn];
char s[maxn],g[maxn];

int main()
{
    //freopen("input.txt","r",stdin);
    REP(i,1,26) g[i]='a'+(i-1);
    REP(i,27,52) g[i]='A'+(i-27);
    REP(i,53,62) g[i]='0'+(i-53);
    int T=read();
    while(T--)
    {
        tot=n=0;
        r=read(),c=read(),k=read();
        REP(i,1,r)
        {
            scanf("%s",s+1);
            REP(j,1,c) a[i][j]=s[j]=='R',tot+=s[j]=='R';
            if(i&1) REP(j,1,c) x[++n]=i,y[n]=j,b[n]=a[i][j];
            else REP_(j,c,1) x[++n]=i,y[n]=j,b[n]=a[i][j];
        }
        int temp=tot/k,cur;
        REP(i,1,k) t[i]=temp;
        REP(i,1,tot-temp*k) t[i]++;
        temp=0,cur=1;
        REP(i,1,k)
        {
            while(temp<t[i])
            {
                ans[x[cur]][y[cur]]=i;
                if(b[cur]) temp++;
                cur++;
            }
            temp=0;
        }
        while(cur<=n) ans[x[cur]][y[cur]]=k,cur++;
        REP(i,1,r)
        {
            REP(j,1,c) printf("%c",g[ans[i][j]]);
            puts("");
        }
    }

    return 0;
}



E Send Boxes to Alice (Hard Version)

题意:给定一个长为n(1e6)的数组a,每一次操作可以把 a[i] 传一个给 a[i+1] 或 a[i-1],问最少需要操作多少次,可以使得存在一个k(k>1),数组a中每个元素可以被k整除(0也可以被k整除,初始a[i]<1e6)。

思路:假设数组a的和为sum,那么满足答案的k一定可以整除sum,进一步想,如果满足答案的k是一个非质数,那么既然k已经满足了,k的质因子一定也可以满足,所以选择质数更优。因此思路就是枚举sum的质因子k,计算需要操作多少次,然后更新答案。

对于某个质数k,原本的操作不好计算,我们考虑a的前缀和s,然后发现,把 a[i] 传一个给 a[i+1],相当于只使得 s[i]–,而传给 a[i-1] 只使得 s[i-1]++,也就是说一次操作只会使得s数组中某一个元素(除了最后一个)改变1,再加上数组a每个元素能被k整除与数组s每个元素能被k整除是等价的,于是问题就变为:对于某个质数k,一次操作可以使得s[i] (i

代码

const int maxn=1e6+5;
int n;
LL s[maxn],ans=1ll<<60;

LL solve(LL k)
{
    LL ret=0;
    REP(i,1,n-1) ret+=min(s[i]%k,k-s[i]%k);
    return ret;
}

bool is_prime(LL k)
{
    for(LL i=2;i*i<=k;i++)
        if(k%i==0) return 0;
    return 1;
}

int main()
{
    //freopen("input.txt","r",stdin);
    n=read();
    REP(i,1,n) s[i]=s[i-1]+read();
    if(s[n]<2) return puts("-1"),0;
    if(is_prime(s[n])) ans=min(ans,solve(s[n]));
    else
    {
        for(LL i=2;i*i<=s[n];i++) if(s[n]%i==0)
        {
            if(is_prime(i)) ans=min(ans,solve(i));
            if(is_prime(s[n]/i)) ans=min(ans,solve(s[n]/i));
        }
    }
    cout<<ans;

    return 0;
}



F Point Ordering

题意

思路:以1-2这条线为界,先用方法2询问n-2次,确定其他点在2的左边还是右边,然后用方法1分别询问共n-2次确定两边最远的点,然后再用方法2分别询问共n-4次确定两边那些点是在最远点的左边还是右边,这样根据距离单调性就可以计算出来了:1 -> 变远 -> 最远 -> 变近 -> 2 -> 变远 -> 最远 -> 变近 -> 1

代码


你可能感兴趣的:(codeforces)