Codeforces #268 Div 1 简要题解

A. 24 Game

题目链接

http://codeforces.com/contest/468/problem/A

题目大意

给你数字 1...n ,每次操作时,你可以从数字中选出两个数做加或减或乘操作,得到一个结果并放回数字堆中。直到最后只剩下一个数字,现在要让最后留下来的那个数字是24,问是否存在一种操作方案,并输出一组可行方案。

思路

显然, n<4 时无解。

n=4,5 时可以手玩出解来。
n>5 时,则可以先用 n=4,5 时的解凑出一个24,然后再凑出很多的数字1,将数字1和数字24相乘耗掉多余的数字

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

int main()
{
    int n;
    scanf("%d",&n);
    if(n<4)
    {
        printf("NO\n");
        return 0;
    }
    printf("YES\n");
    if(n&1)
    {
        for(int i=6;i<=n;i+=2)
            printf("%d - %d = 1\n",i+1,i);
        printf("1 * 2 = 2\n");
        printf("3 + 4 = 7\n");
        printf("7 + 5 = 12\n");
        printf("2 * 12 = 24\n");
        for(int i=6;i<=n;i+=2)
            printf("1 * 24 = 24\n");
    }
    else
    {
        for(int i=5;i<=n;i+=2)
            printf("%d - %d = 1\n",i+1,i);
        printf("1 + 2 = 3\n");
        printf("3 + 3 = 6\n");
        printf("6 * 4 = 24\n");
        for(int i=5;i<=n;i+=2)
            printf("1 * 24 = 24\n");
    }
    return 0;
}

B. Two Sets

题目链接

http://codeforces.com/contest/468/problem/B

题目大意

给你数字 p1...pn ,要你将它们分成两个集合 A,B ,使得 piA,apiA piB,bpiB

思路

此题做法很多,可以用2SAT,DFS等等。这里我选择的是并查集的做法。

建立两个新的元素 pn+1,pn+2 ,若在并查集中, pi pn+1 在同一集合,就表明数字 pi 必须放入集合 A 中。 pi pn+2 在同一集合,就表明数字 pi 必须放入集合 B 中。

在并查集中,若 pi pj 在同一集合,就表明 pi pj 可以被同时放入集合 A B 中。若对于 pi,pj=api pj=bpi ,就在并查集中合并 pi,pj

若最终 pn+1,pn+2 在同一集合,显然矛盾,无解。

然后对于所有的与 pn+1 在同一集合的 pi ,都放入集合 A 中,其他的都放入集合 B

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <map>

#define MAXN 110000
#define MOD 300007

using namespace std;

int f[MAXN];

int findSet(int x)
{
    if(f[x]==x) return x;
    return f[x]=findSet(f[x]);
}

map<int,int>mp;

int n,a,b,p[MAXN],mark[MAXN],tmpmark[MAXN]; //mark[i]&1=1表示第i个数字可以放入A中,mark[i]&2=2表示第i个数字可以放入B中

int main()
{
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++) scanf("%d",&p[i]),mp[p[i]]=i;
    for(int i=1;i<=n+2;i++) f[i]=i;
    for(int i=1;i<=n;i++)
    {
        if(mp.count(a-p[i]))
        {
            int roota=findSet(i),rootb=findSet(mp[a-p[i]]);
            f[roota]=rootb;
        }
        else
        {
            int roota=findSet(i),rootb=findSet(n+2);
            f[roota]=rootb;
        }

        if(mp.count(b-p[i]))
        {
            int roota=findSet(i),rootb=findSet(mp[b-p[i]]);
            f[roota]=rootb;
        }
        else
        {
            int roota=findSet(i),rootb=findSet(n+1);
            f[roota]=rootb;
        }
    }
    if(findSet(n+1)==findSet(n+2))
    {
        printf("NO\n");
        return 0;
    }
    printf("YES\n");
    for(int i=1;i<=n;i++)
        printf("%d ",findSet(i)==findSet(n+2));
    printf("\n");
    return 0;
}

C. Hack it!

题目链接

http://codeforces.com/contest/468/problem/C

题目大意

要你构造 l,r ,使得 ri=lf(i)moda=0
f(i)= 数字 i 的每个数位之和

思路

定义 g(l,r)=ri=lf(i) ,可以得到一个结论:

g(1,10k)+x=g(1+x,10k+x)

显然在区间移动过程中,所有数字 100 10k1 位的数位和没变,第 10k 位的数位和多了 x 个1,因此 g(1+x,10k+x) 多了 x

于是我们可以先求出 g(1,1018)moda 的值,假设为 t ,有公式 g(1,10k)=45k10k1 。然后我们将区间 [1,1018] 右移 at 位,变成 [1+at,1018+at] 即可得到一个可行的区间

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

typedef long long int LL;

int main()
{
    LL a;
    scanf("%I64d",&a);
    LL t=(5*(9*(18*(((LL)1e17)%a)%a)%a)%a+1)%a; //solve(1,1e18)mod a
    printf("%I64d %I64d\n",1+a-t,(LL)1e18+a-t);
    return 0;
}

你可能感兴趣的:(Codeforces #268 Div 1 简要题解)