5.14 浙江省赛vp+791d2

M. BpbBppbpBB

题意:给定两种邮票来组成图形,我们把图形给你问你用了两种邮票各自多少种

思路:我们首先仔细观察邮票的种类,发现如果按照空洞去找规律有这么个规律

按照左上角的原点来代表空洞的话,空洞之间7步之内能到达则是第一种邮票,否则是第二种邮票
AC code
有点丑

#include <iostream>

using namespace std;
#define debug cout<<1<<endl;
const int N = 1e3+100;
char s[N][N];
bool vis[N][N];
int n,m;
int dx[4]={0,7,0,-7};
int dy[4]={7,0,-7,0};
int ans1,ans2;
bool check(int x,int y)
{
    for(int i=x;i<=x+3;i++)
    {
        if(i==x||i==x+3)
        {
            for(int j=y;j<=y+1;j++)
            {
                if(s[i][j]!='.')
                    return false;
            }
            if(s[i][y-1]!='#'||s[i][y+2]!='#')
                return false;
        }
        else
        {
            for(int j=y-1;j<=y+2;j++)
            {
                if(s[i][j]!='.')
                    return false;
            }
            if(s[i][y-2]!='#'||s[i][y+3]!='#')
                return false;
        }
    }
    for(int i=y-2;i<=y+3;i++)
    {
        if(s[x-1][i]!='#')
            return false;
    }
    for(int i=y-2;i<=y+3;i++)
    {
        if(s[x+4][i]!='#')
            return false;
    }
    return true;
}
bool check2(int x,int y)
{
    if(x<=n&&x>=1&&y<=m&&y>=1&&!vis[x][y]&&s[x][y]=='.')
        return true;
    return false;
}
void BFS(int x,int y)
{
    if(vis[x][y])
        return ;
    vis[x][y]=true;
    bool f=true;
    if(check(x,y))
    {
        for(int i=0;i<=3;i++)
        {
            if(check2(dx[i]+x,dy[i]+y)&&check(dx[i]+x,dy[i]+y))
            {
                vis[dx[i]+x][dy[i]+y]=true;
                ans1++;
                f=false;
            }
        }
        if(f)
            ans2++;
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>s[i][j];
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='.'&&!vis[i][j])
            {
                BFS(i,j);
            }
        }
    }
    cout<<ans1<<" "<<ans2<<endl;
    return 0;
}

A. JB Loves Math
题意:给定两个数a和b,问你如果选择一个奇数x和偶数y能都让a每次+x或者-y,需要几步让a变成b

思路:问题转化:ba之前的差值变为0,先分正负,再分奇偶,注意期中3的情况:奇数相加得偶数,但是未必是偶数一定由奇数得来。

#include <bits/stdc++.h>
using namespace std;
int n,m,x,ans;

int main()
{
    int t;
    for(cin>>t;t;t--)
    {
        int a,b;
        cin>>a>>b;
        if(a==b)
            cout<<0<<endl;
        else if(a<b)
        {
            int dis=b-a;
            if(dis%2)
                cout<<1<<endl;
            else
            {
                if((dis/2)%2)
                    cout<<2<<endl;
                else
                    cout<<3<<endl;
            }
        }
        else
        {
            int dis=a-b;
            if(dis%2)
                cout<<2<<endl;
            else
                cout<<1<<endl;
        }
    }
    return 0;
}

C. Rooks Defenders
题意:在矩阵中放上一些rook,选择一片区域,如果这篇区域包含的行列号上有rook则被攻击输出YES否则输出NO
思路:树状数组来维护区间值

#include <bits/stdc++.h>
using namespace std;
int lb(int x)
{
    return ((-x)&(x));
}
const int N = 2e5+100;
int n,q;
int r[N];
int c[N];
int ans[N],anss[N];
void add(int f,int x,int y)
{
    for(int i=x;i<=n;i+=lb(i))
    {
        if(f)
        {
            ans[i]+=y;
        }
        else
        {
            anss[i]+=y;
        }
    }
}
int query(int f,int x)
{
    int sum=0;
    for(int i=x;i;i-=lb(i))
    {
        if(f)
        {
            sum+=ans[i];
        }
        else
        {
            sum+=anss[i];
        }
    }
    return sum;
}
signed main()
{
    cin>>n>>q;
    for(int i=1;i<=q;i++)
    {
        int ch,x,y,x1,y1;
        scanf("%d",&ch);
        if(ch==1)
        {
            scanf("%d%d",&x,&y);
            if(r[x]<1)
            {
                add(1,x,1);
            }
            if(c[y]<1)
            {
                add(0,y,1);
            }
            r[x]++;
            c[y]++;
        }
        else if(ch==2)
        {
            scanf("%d%d",&x,&y);
            r[x]--;
            c[y]--;
            if(r[x]<1)
            {
                add(1,x,-1);
            }
            if(c[y]<1)
            {
                add(0,y,-1);
            }
        }
        else if(ch==3)
        {
            scanf("%d%d%d%d",&x,&y,&x1,&y1);
            if((query(1,x1)-query(1,x-1))>=x1-x+1||(query(0,y1)-query(0,y-1))>=y1-y+1)
            {
                puts("YES");
            }
            else
            {
                puts("NO");
            }
        }
    }
    return 0;
}

B. Stone Age Problem
题意:给定一个数组,我们每次可以有两个操作 :把位置i换成x或者把整个数组换成x,求每次操作后的整个数组的和

思路:思维题,维护每个点操作数

#include <iostream>

using namespace std;
#define int long long
const int N = 2e5+100;
int a[N];
int vis[N];
int cnt,last;
signed main()
{
    int sum=0ll;
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    for(int i=1;i<=q;i++)
    {
        int c,p,x;
        cin>>c;
        if(c==1)
        {
            cin>>p>>x;
            if(vis[p]<cnt)
            {
                sum=sum-last+x;
                vis[p]=cnt;
            }
            else
            {
                sum-=a[p];
                sum+=x;
            }
            a[p]=x;
        }
        else if(c==2)
        {
            cin>>x;
            cnt++;
            last=x;
            sum=x*n;
        }
        cout<<sum<<endl;
    }
    return 0;
}

树形DP复习

选课问题

还是老问题了,树上背包,我们dp设计的是以i为根节点选择m个课的最大得分,别忘记将0设为虚节点后要把背包容量拓展为m+1。因为虚节点0作为根必选了。

#include<bits/stdc++.h>
using namespace std;
const int N =400;
struct node
{
    int nex,to;
};
node edge[N];
int head[N],tot;
void add(int from,int to)
{
    edge[++tot].to=to;
    edge[tot].nex=head[from];
    head[from]=tot;
}
int n,m;
int dp[N][N];
int score[N];
void DFS(int now)
{
    dp[now][1]=score[now];
    for(int i=head[now];i;i=edge[i].nex)
    {
        DFS(edge[i].to);
        for(int j=m+1;j>=1;j--)
        {
            for(int k=0;k<j;k++)
            {
                dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[edge[i].to][k]);
            }
        }
    }
}
signed main()
{
    cin>>n>>m;
    for(int i=1,a,b;i<=n;i++)
    {
        cin>>a>>score[i];
        add(a,i);
    }
    DFS(0);
    cout<<dp[0][m+1]<<endl;
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值