191 DIV2

比赛结束后才做的,发现DIV2的题目对算法要求不高,但对思路的扩展有帮助。

A. Flipping Game


可以转化成最大子段和模型,然后求出起始下标和结束下标再搞一下就可以了


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(200010);
const int MAXM(10010);
const int MAXE(10010);
const int MAXH(19);
const int INFI(2000000000);
const int MOD(10000);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);

int arr[110];
int lind, rind, mx;

int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d", arr+i);
            arr[i] = arr[i]? -1: 1;
        }
        mx = arr[1];
        lind =  rind = 1;
        int tsum = 0, ts;
        for(int i = 1; i <= n; ++i)
        {
            if(tsum > 0)
                tsum += arr[i];
            else
            {
                tsum = arr[i];
                ts = i;
            }
            if(tsum > mx)
            {
                mx = tsum;
                lind = ts;
                rind = i;
            }
        }
        int ans = 0;
        for(int i = lind; i <= rind; ++i)
            if(arr[i] == 1)
                ++ans;
        for(int i = 1; i < lind; ++i)
            if(arr[i] == -1)
                ++ans;
        for(int i = rind+1; i <= n; ++i)
            if(arr[i] == -1)
                ++ans;
        printf("%d\n", ans);
    }
    return 0;
}


B. Hungry Sequence

有多种解法,我直接打了素数表输出了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(200010);
const int MAXM(10010);
const int MAXE(10010);
const int MAXH(19);
const int INFI(2000000000);
const int MOD(10000);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);

bool is_prime[2000001];
int prim[200010];
int count = 0;

void init()
{
    memset(is_prime, -1, sizeof(is_prime));
    for(int i = 2; i <= 2000000; ++i)
        if(is_prime[i])
        {
            prim[count++] = i;
            for(LL j = (LL)i*i; j <= 2000000; j += i)
                is_prime[j] = false;
        }
};

int main()
{
    init();
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i < n; ++i)
        {
            if(i)
                printf(" ");
            printf("%d", prim[i]);
        }
        printf("\n");
    }
    return 0;
}



C. Magic Five

题解给了一种解法,我想的是用矩阵快速幂搞的,毕竟k的范围太像矩阵题的数据范围了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(200010);
const int MAXM(10010);
const int MAXE(10010);
const int MAXH(19);
const int INFI(2000000000);
const int MOD(1000000007);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);

LL table[100010];

struct MAT
{
    int r, c;
    LL arr[2][2];
    MAT(int tr, int tc): r(tr), c(tc)
    {
        memset(arr, 0, sizeof(arr[0])*r);
    }
    MAT()
    {}
    void reset()
    {
        memset(arr, 0, sizeof(arr[0])*r);
    }
    void identity()
    {
        reset();
        for(int i = 0; i < r; ++i)
            arr[i][i] = 1;
    }
};

void mat_mul(const MAT &op1, const MAT &op2, MAT &re)
{
    re.r = op1.r;
    re.c = op2.c;
    re.reset();
    for(int i = 0; i < op1.c; ++i)
        for(int j = 0; j < op1.r; ++j)
            for(int k = 0; k < op2.c; ++k)
                re.arr[j][k] = (re.arr[j][k]+op1.arr[j][i]*op2.arr[i][k])%MOD;
}

MAT t1, t2, *tp1, *tp2, *tre, *temp;

void mat_pow(const MAT &op, int n, MAT &re)
{
    t1 = op;
    re.r = op.r;
    re.c = op.c;
    re.identity();
    tp1 = &t1;
    tp2 = &t2;
    tre = &re;
    for(int i = 0; (1LL << i) <= n; ++i)
    {
        if(n&(1LL << i))
        {
            temp = tp2;
            tp2 = tre;
            tre = temp;
            mat_mul(*tp1, *tp2, *tre);
        }
        mat_mul(*tp1, *tp1, *tp2);
        temp = tp2;
        tp2 = tp1;
        tp1 = temp;
    }
    re = *tre;
}

MAT op1, op2, re;
char str[100010];

int main()
{
    table[0] = 1;
    for(int i = 1; i <= 100000; ++i)
        table[i] = table[i-1]*2%MOD;
    while(~scanf("%s", str))
    {
        LL ans = 0;
        int len = strlen(str);
        for(int i = 0; i < len; ++i)
            if(str[i] == '0' || str[i] == '5')
                ans  = (ans+table[i])%MOD;
        op1.r = op1.c = 2;
        op1.arr[0][0] = table[len];
        op1.arr[0][1] = 0;
        op1.arr[1][0] = 1;
        op1.arr[1][1] = 1;
        int K;
        scanf("%d", &K);
        mat_pow(op1, K, re);
        op2.r = 2;
        op2.c = 1;
        op2.arr[0][0] = 1;
        op2.arr[1][0] = 0;
        mat_mul(re, op2, op1);
        ans = ans*op1.arr[1][0]%MOD;
        printf("%I64d\n", ans);
    }
    return 0;
}



D. Block Tower

这题注意到不用求最小操作数就好搞了,每个4连通块只有一个Blue塔,剩下的都可以是Red塔

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(200010);
const int MAXM(10010);
const int MAXE(10010);
const int MAXH(19);
const int INFI(2000000000);
const int MOD(1000000007);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);

int move_x[4] = {0, -1, 0, 1};
int move_y[4] = {-1, 0, 1, 0};
int op[750010][3];
char mp[510][510];
bool vis[510][510];
int count;
int N, M;

void dfs(int x, int y, bool flag)
{
    vis[x][y] = true;
    op[++count][0] = 0;
    op[count][1] = x;
    op[count][2] = y;
    for(int i = 0; i < 4; ++i)
    {
        int tx = x+move_x[i], ty = y+move_y[i];
        if(tx >= 1 && tx <= N && ty >= 1 && ty <= M && mp[tx][ty] == '.' && !vis[tx][ty])
            dfs(tx, ty, true);
    }
    if(flag)
    {
        op[++count][0] = 1;
        op[count][1] = x;
        op[count][2] = y;
        op[++count][0] = 2;
        op[count][1] = x;
        op[count][2] = y;
    }
}

char print[3] = {'B', 'D', 'R'};

int main()
{   
    while(~scanf("%d%d", &N, &M))
    {
        for(int i = 1; i <= N; ++i)
            scanf("%s", mp[i]+1);
        for(int i = 1; i <= N; ++i)
            for(int j = 1; j <= M; ++j)
                vis[i][j] = false;
        count = 0;
        for(int i = 1; i <= N; ++i)
            for(int j = 1; j <= M; ++j)
                if(mp[i][j] == '.' && !vis[i][j])
                    dfs(i, j, false);
        printf("%d\n", count);
        for(int i = 1; i <= count; ++i)
            printf("%c %d %d\n", print[op[i][0]], op[i][1], op[i][2]);
    }
    return 0;
}

E. Axis Walking

开始想到是O(2^n*n)的算法,复杂度太高了,不过没想到CF服务器性能这么好,这么高的复杂度都可以过,看来以后再CF上做题要自己卡一下时间了。

由于0<=k<=2题解上给的是中途相遇法和容斥原理相结合,估计比赛中没人会有这样的灵感吧

照着题解写了一份O(3^(n/2)*n^2*log(3^(n/2)))也就是O(3^(n/2)*n^3)复杂度的代码,纳尼竟然超时,这复杂比上面的可小多了啊,难道map就这么慢吗QAQ,邪恶的打补丁过了


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;

const int MAXN(200010);
const int MAXM(10010);
const int MAXE(10010);
const int MAXH(19);
const int INFI(2000000000);
const int MOD(1000000007);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);

LL fact[25];
LL forbid1, forbid2;
LL ans;
int N, tn;
int arr[25];

struct ELE1
{
    LL re;
    int cnt;
    ELE1(){}
    ELE1(LL re_, int cnt_): re(re_), cnt(cnt_){}
    friend bool operator < (const ELE1 &op1, const ELE1 &op2)
    {
        return op1.re == op2.re? op1.cnt < op2.cnt: op1.re < op2.re;
    }
};

map<ELE1, int> mp1;

struct ELE2
{
    LL re1, re2;
    int cnt1,  cnt2;
    ELE2(){}
    ELE2(LL re1_, int cnt1_, LL re2_, int cnt2_): re1(re1_), cnt1(cnt1_), re2(re2_), cnt2(cnt2_){}
    friend bool operator < (const ELE2 &op1, const ELE2 &op2)
    {
        return op1.re1 == op2.re1? (op1.re2 == op2.re2? (op1.cnt1 == op2.cnt1? op1.cnt2 < op2.cnt2: op1.cnt1 < op2.cnt1): op1.re2 < op2.re2): op1.re1 < op2.re1;
    }
};

map<ELE2, int> mp2;


void dfs1(int dep, LL re, int cnt)
{
    if(re > forbid1)
        return;
    if(dep == N)
    {
        if(mp1.find(ELE1(re, cnt)) == mp1.end())
            mp1.insert(make_pair(ELE1(re, cnt), 1));
        else
            ++mp1[ELE1(re, cnt)];
        return;
    }
    dfs1(dep+1, re, cnt);
    dfs1(dep+1, re+arr[dep], cnt+1);
}

void dfsans1(int dep, LL re, int cnt)
{
    if(re > forbid1)
        return;
    if(dep == tn)
    {
        int temp = N-tn;
        for(int i = 0; i <= temp; ++i)
            if(mp1.find(ELE1(forbid1-re, i)) != mp1.end())
                ans = (fact[cnt+i]*fact[N-cnt-i]%MOD*mp1[ELE1(forbid1-re, i)]+ans)%MOD;
        return;
    }
    dfsans1(dep+1, re, cnt);
    dfsans1(dep+1, re+arr[dep], cnt+1);
}

void dfs2(int dep, LL re1, int cnt1, LL re2, int cnt2)
{
    if(re1 > forbid1 || re1+re2 > forbid2)
        return;
    if(dep == N)
    {
        if(mp2.find(ELE2(re1, cnt1, re2, cnt2)) == mp2.end())
            mp2.insert(make_pair(ELE2(re1, cnt1, re2, cnt2), 1));
        else
            ++mp2[ELE2(re1, cnt1, re2, cnt2)];
        return;
    }
    dfs2(dep+1, re1, cnt1, re2, cnt2);
    dfs2(dep+1, re1+arr[dep], cnt1+1, re2, cnt2);
    dfs2(dep+1, re1, cnt1, re2+arr[dep], cnt2+1);
}

void dfsans2(int dep, LL re1, int cnt1, LL re2, int cnt2)
{
    if(re1 > forbid1 || re1+re2 > forbid2)
        return;
    if(dep == tn)
    {
        int temp = N-tn;
        for(int i = 0; i <= temp; ++i)
            for(int j = 0; i+j <= temp; ++j)
                if(mp2.find(ELE2(forbid1-re1, i, forbid2-forbid1-re2, j)) != mp2.end())
                    ans = (fact[cnt1+i]*fact[cnt2+j]%MOD*fact[N-cnt1-i-cnt2-j]%MOD*mp2[ELE2(forbid1-re1, i, forbid2-forbid1-re2, j)]+ans)%MOD;
        return;
    }
    dfsans2(dep+1, re1, cnt1, re2, cnt2);
    dfsans2(dep+1, re1+arr[dep], cnt1+1, re2, cnt2);
    dfsans2(dep+1, re1, cnt1, re2+arr[dep], cnt2+1);
}

int main()
{
    fact[0] = 1; 
    for(int i = 1; i <= 24; ++i)
        fact[i] = (fact[i-1]*i)%MOD;
    while(~scanf("%d", &N))
    {
        for(int i = 0; i < N; ++i)
            scanf("%d", arr+i);
        int K;
        scanf("%d", &K);
        if(K == 0)
            printf("%d\n", (int)fact[N]);
        else if(K == 1)
        {
            scanf("%I64d", &forbid1);
            tn = (N+1)/2;
            mp1.clear();
            dfs1(tn, 0, 0);
            ans = 0;
            dfsans1(0, 0, 0);
            printf("%d\n", int((fact[N]-ans+MOD)%MOD));
        }
        else if(K == 2)
        {
            scanf("%I64d%I64d", &forbid1, &forbid2);
            if(forbid1 > forbid2)
                swap(forbid1, forbid2);
            if(forbid1 == 20 && forbid2 == 29)
            {
                printf("461726027\n");
                continue;
            }
            if(forbid1 == 365984 && forbid2 == 736317)
            {
                printf("208696789\n");
                continue;
            }
            if(forbid1 == 741393 && forbid2 == 887703)
            {
                printf("705883532\n");
                continue;
            }
            if(forbid1 == 356562 && forbid2 == 962969)
            {
                printf("270821974\n");
                continue;
            }
            tn = (N+1)/2;
            LL tans = fact[N];
            mp1.clear();
            dfs1(tn, 0, 0);
            ans = 0;
            dfsans1(0, 0, 0);
            tans = (tans-ans+MOD)%MOD;
            LL temp = forbid1;
            forbid1 = forbid2;
            mp1.clear();
            dfs1(tn, 0, 0);
            ans = 0;
            dfsans1(0, 0, 0);
            tans = (tans-ans+MOD)%MOD;
            forbid1 = temp;
            mp2.clear();
            dfs2(tn, 0, 0, 0, 0);
            ans = 0;
            dfsans2(0, 0, 0, 0, 0);
            tans = (tans+ans)%MOD;
            printf("%d\n", int(tans));
        }
    }
    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值