18hun第一次多校

A:Artwork

解题思路:

先将题目给定的“黑带”一条条画到图上去,此时可以通过广搜(深搜会爆)得到“联通块”的个数为n,然后我们反过来将“黑带”一条条消除。先消除一个“黑块”,若黑块附近没有任何白块,此时“联通块”的个数加一,即n+1,若黑块附近存在白块,记录不同“白色联通块”的种数s,此时“联通块个数”为n-s+1,最后合并这些“白色联通块”。若我们通过标数字的方法来表示“联通块”,那么对“联通块”合并时肯定会超时(最差0(n)),所以我们使用并查集来合并这些“联通块”(0(lgn))。

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>

using namespace std;

const int N = 1010;
const int M = 10010;

int graph[N][N],parent[N*N],vec[M];
struct Node{
    int x1,y1,x2,y2;
}node[M];
int n,m,q;
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};

void init()
{
    memset(graph,0,sizeof(graph));
    for(int i = 0; i < N*N; ++i) parent[i] = i;
}

bool inside(int x,int y)
{
    return x >= 1 && x <= n && y >= 1 && y <= m;
}

int id(int x,int y)
{
    return (x-1)*m+y;
}

int find(int x)
{
    while(x != parent[x]){
        parent[x] = parent[parent[x]];
        x = parent[x];
    }
    return x;
}

void merge(int x,int y)
{
    int i = find(x);
    int j = find(y);
    if(i != j)
        parent[i] = j;
}

int solve(int x,int y,int ans)
{
    graph[x][y]--;
    int flag = 0;
    set<int>st;
    if(graph[x][y] == 0){
        for(int i = 0; i < 4; ++i){
            int nx = x+dx[i];
            int ny = y+dy[i];
            if(inside(nx,ny) && graph[nx][ny] == 0){
                merge(id(x,y),id(nx,ny));
                flag = 1;
                st.insert(find(id(nx,ny)));
            }
        }
        if(flag) ans = ans-st.size()+1;
        else ans++;
    }
    return ans;
}

int main()
{
//    freopen("D:\\12.in","r",stdin);
//    freopen("D:\\out.txt","w",stdout);
    while(~scanf("%d%d%d",&n,&m,&q)){
        init();
        for(int i = 1; i <= q; ++i){
            scanf("%d%d%d%d",&node[i].x1,&node[i].y1,&node[i].x2,&node[i].y2);
            for(int j = node[i].x1; j <= node[i].x2; ++j)
                for(int k = node[i].y1; k <= node[i].y2; ++k)
                    graph[j][k]++;
        }

        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= m; ++j){
                if(!graph[i][j] && inside(i,j+1) && !graph[i][j+1]) merge(id(i,j),id(i,j+1));
                if(!graph[i][j] && inside(i+1,j) && !graph[i+1][j]) merge(id(i,j),id(i+1,j));
            }
        }

        int ans = 0;
        for(int i = 1; i <=n ; ++i){
            for(int j = 1; j <= m; ++j){
                if(!graph[i][j] && id(i,j) == find(id(i,j))) ans++;
            }
        }

        vec[q] = ans;

        for(int i = q; i > 1; --i){
            for(int j = node[i].x1; j <= node[i].x2; ++j){
                for(int k = node[i].y1; k <= node[i].y2; ++k){
                    ans = solve(j,k,ans);
                }
            }
            vec[i-1] = ans;
        }

        for(int i = 1; i <= q; ++i)
            printf("%d\n",vec[i]);
    }
    return 0;
}

/**********************************************************************
	Problem: 2022
	User: zhiyuanjiang
	Language: C++
	Result: AC
	Time:432 ms
	Memory:10192 kb
**********************************************************************/


D:Daydreaming Stockbroker

解题思路:

贪心,在股价最低点买入,最高点卖出,最多能操作的股票数目为100000

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long llt;
const int N = 400;

llt data[N];

int main()
{
    int n;
    while(~scanf("%d",&n)){
        for(int i = 1; i <= n; ++i)
            scanf("%lld",&data[i]);

        llt money = 100,stnum = 0,price = 600;
        int i = 1;
        while(i <= n){
            while(i <= n && price >= data[i]){
                price = data[i]; i++;
            }
            stnum = money/data[--i];
            if(stnum > 100000) stnum = 100000;
            money -= stnum*data[i];
            price = data[i];

            while(i <= n && price <= data[i]){
                price = data[i]; i++;
            }
            money += stnum*data[--i];
            stnum = 0;
            price = data[i];

            i++;
        }

        money += stnum*price;
        printf("%lld\n",money);
    }
    return 0;
}

/**********************************************************************
	Problem: 2026
	User: zhiyuanjiang
	Language: C++
	Result: AC
	Time:4 ms
	Memory:2024 kb
**********************************************************************/


E:Exponial

解题思路:

指数循环节,第一次写这种题,一直弄不懂为啥有时不满足那个判断条件的情况下也能用这玩意,数学好难大哭

扫描二维码关注公众号,回复: 1024052 查看本文章

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>

using namespace std;

typedef long long llt;

const int N = 1010;
const int M = 10010;

llt phi(llt n)
{
    llt ans = n;
    for(int i = 2; i*i <= n; ++i){
        if(n%i == 0)
            ans = ans-ans/i;
        while(n%i == 0)
            n /= i;
    }
    if(n > 1)
        ans = ans-ans/n;
    return ans;
}

llt fast_mi(llt x,llt n,llt mod)
{
    llt ans = 1;
    while(n){
        if(n&1) ans = ans*x%mod;
        n >>= 1;
        x = x*x%mod;
    }
    return ans;
}

llt expoinal(llt x,llt mod)
{
    if(mod == 1) return 0;
    if(x == 1) return 1%mod;
    if(x == 2) return 2%mod;
    if(x == 3) return 9%mod;
    if(x == 4) return fast_mi(4,9,mod);

    llt r = phi(mod);
    llt ans = expoinal(x-1,r)+r;
    ans = fast_mi(x,ans,mod);

    return ans;
}

int main()
{
//    freopen("D:\\in1.in","r",stdin);
//    freopen("D:\\out.txt","w",stdout);
    llt n,m;
    while(~scanf("%lld%lld",&n,&m)){
        printf("%lld\n",expoinal(n,m));
    }
    return 0;
}

/**********************************************************************
	Problem: 2021
	User: zhiyuanjiang
	Language: C++
	Result: AC
	Time:4 ms
	Memory:2024 kb
**********************************************************************/


F:Fleecing the Raffle

解题思路:官方题解如下


只要求出上面“1式”大于1的临界条件即可,x = n/(p-1)

数学菜呀,这里看了好久才看明白大哭

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long llt;
const int N = 10010;
const double esp = 1e-6;

//lgamma(n):求ln((n-1)!);
//tgamma(n):求(n-1)!

int main()
{
    int n,p;
    while(~scanf("%d%d",&n,&p)){
        double x = n/(p-1);
        double ans = x*p;
        ans *= exp(lgamma(n+1)+lgamma(n+x-p+1)-lgamma(n-p+2)-lgamma(n+x+1));
        printf("%.9f\n",ans);
    }
    return 0;
}


G:Game Rank

解题思路:

模拟题,完善一个等级系统,在25级到6级时,赢得一场获得一颗星,若连续赢三场以上,额外多获得一颗星。每输一场,若等级低于20,或在20级且没有一颗星,没有影响,否则减少一颗星。达到lengend级别无论输赢没有任何影响。

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long llt;
const int N = 10010;

int rk[30];
char data[N];

void init()
{
    for(int i = 21; i <= 25; ++i) rk[i] = 2;
    for(int i = 16; i <= 20; ++i) rk[i] = 3;
    for(int i = 11; i <= 15; ++i) rk[i] = 4;
    for(int i = 1;  i <= 10; ++i) rk[i] = 5;
}

int main()
{
    init();
    while(~scanf(" %s",data)){
        int r = 25,star = 0;
        int tick = 0;  //没有连续3个w
        for(int i = 0; i < strlen(data); ++i){
            if(data[i] == 'W'){
                tick++;
                if(r == 1 && star == 5){
                    r = 0; break;
                }
                if(tick >= 3 && r >= 6) star += 2;
                else star++;
                if(star > rk[r]){
                    star -= rk[r];
                    r--;
                }
            }else{
                tick = 0;
                if(r > 20 || (r == 20 && star == 0));
                else{
                    if(star == 0){
                        r++; star = rk[r]-1;
                    }else{
                        star--;
                    }
                }
            }
        }
        if(r) printf("%d\n",r);
        else printf("Legend\n");
    }
    return 0;
}

/**********************************************************************
	Problem: 2018
	User: zhiyuanjiang
	Language: C++
	Result: AC
	Time:4 ms
	Memory:2032 kb
**********************************************************************/


J:Jumbled Compass

解题思路:

水题,比较往哪个方向旋转角度小。

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        if(n > m) m += 360;
        int d1 = m-n;
        int d2 = d1-360;
        if(abs(d1) < abs(d2))
            printf("%d\n",d1);
        else
            printf("%d\n",d2);
    }
    return 0;
}

/**********************************************************************
	Problem: 2025
	User: zhiyuanjiang
	Language: C++
	Result: AC
	Time:0 ms
	Memory:2024 kb
**********************************************************************/


猜你喜欢

转载自blog.csdn.net/jiangzhiyuan123/article/details/79815823