第一天2233

1.进制转换

2.顺子日期
在这里插入图片描述
3.刷题统计
在这里插入图片描述

#include<iostream>
using namespace std;
#define ll long long
int main()
{
    ll a, b, n;
    cin >> a >> b >> n;
    ll week = a * 5 + b * 2;
    ll ans = n / week * 7;
    n %= week;
    for (int i = 1; i <= 5; i++)
    {
        if (n > 0)
            n -= a, ans++;
    }
    for (int i = 1; i <= 2; i++)
    {
        if (n > 0)
            n -= b, ans++;
    }
    cout << ans << endl;
    //system("pause");
    return 0;
}


4.修剪灌木
在这里插入图片描述

#include<iostream>
using namespace std;
int main()
{
    int n;
    cin >> n;
    int t = n * 2 - 2;
    for (int i = 1; i <= n / 2; i++)
    {
        cout << t << endl;
        t -= 2;
    }
    if ((n & 1) == 0)
        t += 2;
    for (int i = n / 2 + 1; i <= n; i++)
    {
        cout << t << endl;
        t += 2;
    }
    //system("pause");
    return 0;
}

5.X进制减法在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 1e6 + 7;
const int mod = 1000000007;
int n, m;
int a[N], b[N];

int main()
{
    scanf("%d%d", &n, &n);
    for (int i = n; i; i--)
        scanf("%d", a + i);
    scanf("%d", &m);
    for (int i = m; i; i--)
        scanf("%d", b + i);
    long long ans = 0;
    for (int i = n; i; i--)
    {
        ans = ans * max(2, max(a[i] + 1, b[i] + 1)) % mod;
        ans = ((ans + a[i] - b[i]) % mod + mod) % mod;
    }
    printf("%lld\n", ans);
    //system("pause");
    return 0;
}

6.统计子矩阵
在这里插入图片描述

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 500 + 7;

int n, m;
int k;
int a[N][N];
int s[N][N];
signed main()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            scanf("%d", &a[i][j]);
            s[i][j] = s[i - 1][j] + a[i][j];
        }
    }
    long long ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = i; j <= n; j++)
        {
            for (int l = 1, r = 1, sum = 0; r <= m; r++)
            {
                sum += s[j][r] - s[i - 1][r];
                while (sum > k)
                    sum -= s[j][l] - s[i - 1][l++];
                ans += r - l + 1;
            }
        }
    }
    printf("%lld\n", ans);
    //system("pause");
    return 0;
}

思路:枚举 起始行 和 行数 ,然后遍历列,得到了一个长度为 m 的一维的数组,在这个数组中用双指针优化。

7.积木画
在这里插入图片描述

//状压DP
#include<iostream>
using namespace std;
const int mod = 1e9 + 10;
int n;
long long dp[2][4], l, now = 1;
int main()
{
    cin >> n;
    dp[l][3] = 2;
    dp[l][0] = dp[l][1] = dp[l][2] = 1;
    while (--n)
    {
        dp[now][0] = dp[l][3];
        dp[now][1] = (dp[l][0] + dp[l][2]) % mod;
        dp[now][2] = (dp[l][0] + dp[l][1]) % mod;
        dp[now][3] = (dp[l][0] + dp[l][2] + dp[l][1] + dp[l][3]) % mod;
        swap(l, now);
    }
    cout << dp[l][0] << endl;
    //system("pause");
    return 0;
}

思路:
状压:
dp[now][0]代表当前列刚好填满
dp[ now ][1]代表当前列填满并向下一列突出了上面的一格
dp[now][2] 代表当前列填满并向下一列突出了下面的一格
dp[now][3] 代表当前列填满并向下一列突出两格。
dp[la]代表上一列

状态转移:
当前列填满:上一列填满并向下一列(当前列)填两格。
当前列填满并上凸一格:上一列填满加上上一列填满并下凸。
当前列填满并下凸一格:上一列填满加上上一列填满并上凸。
当前列填满并向下一列突出两格:所有情况相加。

8.扫雷
(可恶的卡常)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <unordered_map>
using namespace std;
 
const int maxn=50010;
struct Node
{
    int x,y,r;
    int cnt;
 
    Node (int _x,int _y) : x(_x),y(_y){}
    Node (int _x,int _y,int _r) : x(_x),y(_y),r(_r){}
    Node (int _x,int _y,int _r,int _cnt) :x(_x),y(_y),r(_r),cnt(_cnt){}
    Node()=default;
    bool operator < (Node const & a) const
    {
        if(x!=a.x)
            return x<a.x;
        return y<a.y;
    }
}cir[maxn];
struct comp
{
    int operator()(const std::pair<int, int>& p) const {
        return p.first ^ p.second;  //返回值为bool,比较符为&,|都比这一个慢,
    }
};
typedef long long LL;
LL squ(int x)
{
    return (LL) x*x;
}
vector<int> adj[maxn];
unordered_map<pair<int,int> ,int,comp> ump;
bool vis[maxn]={false};
int n,m;
int dfs_Trave(int x,int y,int r);
int dfs(int index);
void add(int index);
int main()
{
    scanf("%d%d",&n,&m);
    int x,y,r;
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d%d",&x,&y,&r);
        auto temp=ump[{x,y}];
        if(temp!=0)
        {
           cir[temp].r=max(cir[temp].r,r);
           cir[temp].cnt++;
        }
        else
        {
            cir[i]={x,y,r,1};   
            ump[{x,y}]=i;      
        }
    }
    sort(cir+1,cir+n+1);
 
    for(int i=1;i<=n;++i)
    {
        add(i);
    }
    int res=0;
    for(int i=0;i<m;++i)
    {
        scanf("%d%d%d",&x,&y,&r);
        res+=dfs_Trave(x,y,r);
    }
 
    printf("%d\n",res);
    system("pause");
    return 0;
}
 
void add(int index)
{
    for(int i=index-1;i>0;--i)
    {
        if(squ(cir[index].r)<squ(cir[i].x-cir[index].x))
            break;
        if(squ(cir[index].r)>=squ(cir[i].x-cir[index].x)+squ(cir[i].y-cir[index].y))
            adj[index].push_back(i);
    }
 
    for(int i=index+1;i<=n;++i)
    {
        if(squ(cir[index].r) < squ(cir[i].x-cir[index].x))
           break;
        if(squ(cir[index].r) >= squ(cir[i].x-cir[index].x)+squ(cir[i].y-cir[index].y))
            adj[index].push_back(i);
    }
}
 
int dfs(int index)
{
    int sum=cir[index].cnt;
    vis[index]=1;
    for(int i=0;i<adj[index].size();++i)
    {
        int v=adj[index][i];
        if(vis[v]==0)
            sum+=dfs(v);
    }
    return sum;
 
}
 
int dfs_Trave(int x,int y,int r)
{
    Node e1={x-r,y,r},e2={x+r,y,r};
    int l=lower_bound(cir+1,cir+n+1,e1)-cir;
    int ri=lower_bound(cir+1,cir+n+1,e2)-cir;
    l=min(l,n),ri=min(ri,n);
    int sum=0;
    for(int i=l;i<=ri;++i)
    {
        if(i==0)
            continue;
        if((squ(r)>=squ(cir[i].x-x)+squ(cir[i].y-y))&&vis[i]==0)
            sum+=dfs(i);
    }
    return sum;
}

思路:转换成有向图的遍历问题,(在爆炸范围内就建一条单边,遍历有向图,判断点上有没有雷),要用哈希。

9.李白打酒加强版
在这里插入图片描述

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
ll dp[110][110][110];
int t;
int main()
{
    cin>>t;
    while(t--){
        int n, m;
        scanf("%d%d", &n, &m);
        dp[n][m][2] = 1;
        for (int i = n; i >= 0; i--)
        {
            for (int j = m; j >= 0; j--)
            {
                for (int k = 0; k <= m; k++)
                {
                    if (i && k*2 <= m)
                        dp[i - 1][j][k*2] = (dp[i - 1][j][k*2] + dp[i][j][k]) % mod;
                    if (k && j)
                        dp[i][j - 1][k - 1] = (dp[i][j - 1][k - 1] + dp[i][j][k]) % mod;
                }
            }
        }
        printf("%lld\n", dp[0][1][1]);
        for(int i=0;i<110;i++)
            for(int j=0;j<110;j++)
                 for(int k=0;k<110;k++)
                    dp[i][j][k] = 0;
    }
    //system("pause");
    return 0;
}

思路:dp
状态表示:
dp[i][j][k]代表 有 i 家店没有遇到,j 朵花没有看,壶中有 k 斗酒的方案数.
转移方程:
if (i && k2 <= m)
dp[i - 1][j][k
2] = (dp[i - 1][j][k*2] + dp[i][j][k]) % mod;
if (k && j)
dp[i][j - 1][k - 1] = (dp[i][j - 1][k - 1] + dp[i][j][k]) % mod;
10.砍竹子

在这里插入图片描述

#include<iostream>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
long long msq(long long x) // 手写开根
{
    long long  r = sqrt(x) + 10;
    for (long long  i = max(0ll, r - 20); i <= r; i++)
    {
        if (i * i > x)
            return i - 1;
    }
    return r - 10;
}
int main()
{
    int n;
    scanf("%d", &n);
    vector<long long> v[2];
    int now = 0, la = 1;
    long long  ans = 0;
    while (n--)
    {
        long long t;
        scanf("%lld", &t);
        v[now].clear();
        while (t > 1)
        {
            v[now].push_back(t);
            t = msq(t / 2 + 1);
        }
        ans += v[now].size();
        for (int i = 0; i < v[now].size(); i++)
        {
            for (int j = 0; j < v[la].size(); j++)
            {
                if (v[now][i] == v[la][j])
                {
                    ans -= v[now].size() - i;
                    goto g;
                }
            }
        }
    g:
        swap(now, la);
    }
    printf("%lld\n", ans);
    //system("pause");
    return 0;
}

思路:贪心,枚举
核心结论:使用魔法来砍所减少的次数就是每对相邻竹子的公共的路程 , 枚举每个相邻的竹子所到的点即可

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值