Codeforces Round #209 (Div. 2)思路


A. Table

简单题。



#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
using namespace std;

int main()
{
    int n, m, ans;
    scanf("%d%d", &n, &m);
    int x;
    ans = n*m;
    for (int i=1; i<=n; ++i) for(int j=1; j<=m; ++j)
    {
        scanf("%d", &x);
        if (x)
        {
            if (1==i || 1==j || i==n || j==m) ans = 2;
            else ans = min(ans, 4);
        }
    }
    printf("%d\n", ans);
}

B. Permutation

算发现规律吧。

对于.后面的一个式,保持结果为n;前面的式子大小范围为[n,(n+1)+(n+2)...+(n+n) - (1+2+3...+n)], 所以,只要调整前面式子,让结果为2k+n(因为0<=k<=n/2)。

如:

1 2 3 4  结果为 2 - 2 = 0,调换1 3位置,结果为4 - 2 = 2;

每被4整除的连续4个数中,调换1 3位置,值就增加2。



#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
using namespace std;

#define clr(p,v) memset(p,v,sizeof(p))
const int maxn = 110 ;
const int maxm = 1000010 ;

int n, m, ans, res, k;
int d[maxn];
bool vis[maxn], used[maxn];

void init()
{
    ans = res = 0;
    clr(vis, 0);
    clr(used, 0);
    clr(d, 0);
}

int main()
{
    scanf("%d%d", &n, &k);
    int cnt = 0;
    for (int i=1; i<=k; ++i)
    {
        cnt += 4;
        int x = (i-1)*4+1;
        printf("%d %d %d %d ", x+2, x+1, x, x+3);
    }
    for(int i=cnt+1; i<=n+n; ++i)
        printf("%d ", i);
    puts("");
    
    return 0;
}

C. Prime Number

通分后,

分母 =  x^(a1+a2+...an)

分子 = x^(a2+a3+...an) + x^(a1+a3+...an) + ... + x^(a2+a3+...a(n-1))

找公约数,从分子下手,提取公因式,观察可了解到,都是x^n次方,所以,找最小的n即可(注意有多个最小,要把最小的相加,可能比第2小大,所以,要再判断,循环这个过程)



#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;

#define clr(p,v) memset(p,v,sizeof(p))
const int maxn = 100010 ;
const int mod = 1000000007 ;
typedef __int64 LL;

int n;
LL x, sum, ans;
LL d[maxn];
map<LL, LL> mp;
map<LL, LL>::iterator iter;

void Init()
{
    mp.clear();
    sum = 0;
}

void Input()
{
    scanf("%d%I64d", &n, &x);
    for (int i=1; i<=n; ++i)
    {
        scanf("%I64d", &d[i]);
        sum += d[i];
    }
}

LL QuickPow(LL x, LL num)
{
    if (num == 0)
        return 1;
    if (num == 1)
        return x;
    if (num % 2 == 1)
    {
        return x*QuickPow(x, num-1)%mod;
    }
    else
    {
        LL tmp = QuickPow(x, num>>1)%mod;
        return tmp*tmp%mod;
    }
    /*
    LL ans = 1;
    while (num)
    {
        if (1 == num % 2)
            ans = ans*x%mod;
        x = x*x%mod;
        num >>= 1;
    }
    return ans % mod;
    */
}

void Solve()
{
    ans = sum;
    for (int i=1; i<=n; ++i) ++mp[sum - d[i]];
    for (iter = mp.begin(); iter != mp.end(); ++iter)
    {
        if (iter->second >= x)
        {
            mp[iter->first + 1] += (iter->second)/x;
            (iter->second) %= x;
        }
        if (iter->second)
        {
            ans = min(ans, iter->first);
            break;
        }
    }
    ans = QuickPow(x, ans);
}

void Output()
{
    printf("%I64d\n", ans);
}

int main()
{
    Init();
    Input();
    Solve();
    Output();
    return 0;
}

D. Pair of Numbers

换种思维方式,不要从下面入手,找连续区间内,存在一个能被其他所有数整除。

假设这个数是ai,从i向两端扩展,找到不能被ai整除的最左l,最右r位置,并记录这两个端点。

if (y % x == 0 && z % y == 0)   =>  z % x == 0 利用这个性质,x能被y整除时,下个数就直接跳到端点之后一个数处理;如果不能整除,也就到达端点。

(该方法可解答http://acm.fzu.edu.cn/problem.php?pid=2136)



/*
题意:
    给出长度为N的整形数组,找出所有 Max(r-l) 中存在一个数能被其他所有数整除
思路:
    假设以i为那个数,向两边扩展l[i], r[i]
    if (r[i-1] % r[i] == 0 )  l[i] = i-l[i-1] + L;
    else l[i] += 0;
    
    同理,r[i]
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

#define clr(p,v) memset(p, v, sizeof(p))
const int maxn = 300010 ;
const int mod = 1000000007 ;

int n, cnt, mx;
int d[maxn], ans[maxn];
int l[maxn], r[maxn];
bool vis[maxn];

void Init()
{
    cnt = 0;
    mx = 1;
    d[0] = mod;
    clr(vis, false);
}

void Input()
{
    scanf("%d", &n);
    for (int i=1; i<=n; ++i)
        scanf("%d", &d[i]);
}

void Solve()
{
    // temp int
    int iMid;
    // left
    l[1] = 0;
    for (int i=2; i<=n; ++i)
    {
        iMid = i-1;
        if (d[iMid] % d[i] == 0)
        {
            while(1)
            {
                iMid = l[iMid];
                if (!iMid || d[iMid] % d[i] != 0)
                    break;
            }
        }
        l[i] = iMid;
    }
    // right
    r[n] = n;
    for (int i=n-1; i; --i)
    {
        iMid= i+1;
        if (d[iMid] % d[i] == 0)
        {
            while (1)
            {
                iMid = r[iMid] + 1;
                if (iMid > n || d[iMid] % d[i] != 0)
                    break;
            }
        }
        r[i] = --iMid;
    }
    // get ans
    for (int i=1; i<=n; ++i)
    {
        if (mx < r[i] - l[i])
        {
            mx = r[i] - l[i];
            cnt = 0;
            ans[cnt++] = l[i]+1;
        }
        else if (mx == r[i] - l[i])
        {
            ans[cnt++] = l[i]+1;
        }
    }
    // remove reused
    iMid = 0;
    for (int i=0; i<cnt; ++i)
    {
        if (!vis[ans[i]])
        {
            vis[ans[i]] = true;
            ans[iMid++] = ans[i];
        }
    }
    cnt = iMid;
}

void Output()
{
    printf("%d %d\n", cnt, mx-1);
    for (int i=0; i<cnt; ++i) printf("%d ", ans[i]);
    puts("");
}

int main()
{
    Input();
    Init();
    Solve();
    Output();
    return 0;
}

E. Neatness



/*
题意:
    要关掉所有房间的灯,一个步骤要么开灯,要么关灯,要么向有灯的方向前进一格。输出一种关掉所有灯的方案。不能关掉所有灯输出NO
解题思路:
    dfs,搜索时,点灯,回退时,关灯
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
using namespace std;

#define clr(p,v) memset(p,v,sizeof(p))
const int maxn = 505 ;
const int maxm = 1000010 ;

int n, sx, sy, sum, cnt;
int mk[maxn][maxn];
char str[maxm];
int dx[] = {0, 0, 1, -1};
int dy[] = {-1, 1, 0, 0};
char forward[] = {'L', 'R', 'D', 'U'};
char back[] = {'R', 'L', 'U', 'D'};
bool vis[maxn][maxn];

void Init()
{
    cnt = 0;
    sum = 0;
    clr(vis, false);
}

void Input()
{
    scanf("%d%d%d", &n, &sx, &sy);
    for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j)
    {
        scanf("%d", &mk[i][j]);
        sum += mk[i][j];
    }
}

bool IsOut(int x, int y)
{
    if (x<1 || y<1 || x>n || y>n)
        return true;
    return false;
}

bool Can(int x, int y, int i)
{
    while (1)
    {
        if (IsOut(x, y) || vis[x][y])
            return false;
        if (1 == mk[x][y])
            return true;
        x += dx[i];
        y += dy[i];
    }
}

void dfs(int x, int y)
{
    if (0 == mk[x][y])
    {
        mk[x][y] = 1;
        str[cnt++] = '1';
        ++sum;
    }
    vis[x][y] = true;
    for (int i=0; i<4; ++i)
    {
        int tx = x + dx[i];
        int ty = y + dy[i];
        if (IsOut(tx, ty) || vis[tx][ty] || !Can(tx, ty, i))
            continue;
        str[cnt++] = forward[i];
        dfs(tx, ty);
        str[cnt++] = back[i];
    }
    str[cnt++] = '2';
    --sum;
}

void Output()
{
    if (0 == sum)
    {
        str[cnt++] = '\0';
        puts("YES");
        puts(str);
    }
    else
    {
        puts("NO");
    }
}

int main()
{
    Init();
    Input();
    dfs(sx, sy);
    Output();
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值