ABC326 D-F

比赛链接

目录

D - ABC Puzzle

tag:搜索,剪枝,dfs

思路:

题解:

E - Revenge of "The Salary of AtCoder Inc."

tag:概率,期望

解答:

F - Robot Rotation

tag:DFS

题解:


D - ABC Puzzle

tag:搜索,剪枝,dfs

思路:

赛中的时候就大概算了4^25,感觉这个复杂度dfs基本不可能,所以我就放弃了,但是我们仔细观察可以发现,他每一行和每一列的合法情况不多,因为ABC只能出现一次,而且还要满足给出的两个字符串,粗略估计一下大概为(_{5}^{3}\textrm{C} * 2 ) ^ 5,因此我们再加上剪枝肯定是可以满足的。

题解:

初始化为'.',然后dfs一遍,每次判断是否满足当前条件,如果不满足则直接返回,完成剪枝操作,避免重复计算加大计算量,用到了大量的变量来判断条件,这个题比较考验码力,具体如代码所示。

// 加油昂!!!
// Problem: D - ABC Puzzle
// Contest: AtCoder - Panasonic Programming Contest 2023(AtCoder Beginner Contest 326)
// URL: https://atcoder.jp/contests/abc326/tasks/abc326_d
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 2e5 + 5, M = 1e9 + 7, mod = 998244353;
#define YES {cout<<"YES"<<endl;return ;}
#define NO {cout<<"NO"<<endl;return ;}
int n, m, k;
string R, C;
char p[5][5];
bool fx[5], fy[5];
bool fx1[5][3], fy1[5][3];
bool flag = false;
int sum[5];
bool f[5];
void dfs(int x, int y)
{
    if (flag) return;
    if (x == n)
    {
        cout << "Yes" << "\n";
        flag = true;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
                cout << p[i][j];
            cout << "\n";
        }
        return ;
    }
    for (int i = 0; i < 3; i++)
    {
        char c = 'A' + i;
        if (fx1[x][i] == true) continue;
        if (fy1[y][i] == true) continue;
        if (!fx[x] && c != R[x]) continue;
        if (!fy[y] && c != C[y]) continue;
        p[x][y] = c;
        sum[x] += (i + 1);
        bool f1 = fx[x], f2 = fy[y], f3 = fx1[x][i], f4 = fy1[y][i];
        fx[x] = fy[y] = fx1[x][i] = fy1[y][i] = true;
        if (y + 1 < n) dfs(x, y + 1);
        else if (sum[x] == 6) dfs(x + 1, 0);
        sum[x] -= (i + 1);
        fx[x] = f1, fy[y] = f2, fx1[x][i] = f3, fy1[y][i] = f4;
        p[x][y] = '.';
    }
    if (y + 1 < n) dfs(x, y + 1);
    else if (sum[x] == 6) dfs(x + 1, 0);
}
void solve()
{
    cin >> n;
    cin >> R >> C;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
            p[i][j] = '.';
    }
    dfs(0,0);
    if (!flag) cout << "No\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    //cin >> t;
    while (t--)
        solve();
    return 0;
}

E - Revenge of "The Salary of AtCoder Inc."

tag:概率,期望

解答:

每一个数能够由前面所有的数转移得到,第一个数得到的概率是\frac{1}{n},第二个数是\frac{1}{n^{2}} + \frac{1}{n},……,以此类推,可以发现递推公式p(i) = \sum_{1}^{i - 1}p(i) * \frac{1}{n} + \frac{1}{n},然后答案为ans = \sum_{1}^{n}p(i) * A(i)

// 加油昂!!!
// Problem: E - Revenge of "The Salary of AtCoder Inc."
// Contest: AtCoder - Panasonic Programming Contest 2023(AtCoder Beginner Contest 326)
// URL: https://atcoder.jp/contests/abc326/tasks/abc326_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 3e5 + 5, M = 1e9 + 7, mod = 998244353;
#define YES {cout<<"YES"<<endl;return ;}
#define NO {cout<<"NO"<<endl;return ;}
int n, m, k;
int p[N];
int quick_mi(int a, int b, int p)
{
    int ans = 1 % p;
    while(b)
    {
        if (b & 1) (ans *= a) %= p;
        (a *= a) %= p;
        b >>= 1;
    }
    return ans;
}
void solve()
{
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    int ni = quick_mi(n, mod - 2, mod);
    p[0] = ni;
    int ans = 0;
    for (int i = 0; i < n; i++)
    {
        if (i) (p[i] = p[i - 1] * ni + ni) %= mod;
        (ans += p[i] * a[i] % mod) %= mod;
        if (i) (p[i] += p[i - 1]) %= mod;
    }
    cout << ans << "\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    //cin >> t;
    while (t--)
        solve();
    return 0;
}

F - Robot Rotation

tag:DFS

题解:

这个题可以看出是按照下标奇偶性分开,转换为一个问题,给定一个长度为n/2的序列,能否通过改变符号使之和等于给定数字,并且要给出改变了哪一些,只要我们知道了改变的是什么,那么方向的改变也很好求。数据范围可以看出不能直接使用dfs,因为一半的序列长度都是40。所以需要双向dfs,但是我这里写的这个拆开的写法应该不算是双向dfs,我估摸复杂度应该也是和不拆开一样的,但是过了,需要dfs四次,然后再遍历一遍dfs出的所有解,再用4个map存下来,并遍历其中map和其对应的map求解,如果加起来满足答案,那么就将其存储下来结束循环,否则就不行具体见代码:

// 加油昂!!!
// Problem: F - Robot Rotation
// Contest: AtCoder - Panasonic Programming Contest 2023(AtCoder Beginner Contest 326)
// URL: https://atcoder.jp/contests/abc326/tasks/abc326_f
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 2e5 + 5, M = 1e9 + 7, mod = 998244353;
#define YES {cout<<"YES"<<endl;return ;}
#define NO {cout<<"NO"<<endl;return ;}
int n, X, Y;
int res[4];
unordered_map<int,vector<int>> mp[4];
vector<int> a(85);
vector<int> now[4];
int all[4];
void dfs(int i)
{
    int ne = i % 4;
    if ((int)now[ne].size() == res[ne])
    {
        mp[ne][all[ne]] = now[ne];
        return ;
    }
    all[ne] += a[i];
    now[ne].push_back(1);
    dfs(i + 4);
    all[ne] -= a[i] * 2;
    now[ne][now[ne].size() - 1] = -1;
    dfs(i + 4);
    now[ne].erase(--now[ne].end());
    all[ne] += a[i];
}
void solve()
{
    cin >> n >> X >> Y;
    for (int i = 0; i < 4; i++)
    {
        res[i] = (n + 4 - i - 1) / 4;
    }
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    dfs(0);
    dfs(1);
    dfs(2);
    dfs(3);
    vector<int> ansy[2];
    bool f = false;
    for (auto &[x,y] : mp[0])
    {
        if (mp[2].count(Y - x)) 
        {
            ansy[0].insert(ansy[0].end(), y.begin(), y.end());
            ansy[1].insert(ansy[1].end(), mp[2][Y - x].begin(), mp[2][Y - x].end());
            f = true;
            break;
        } 
    }
    if (!f) 
    {
        cout << "No\n";
        return ;
    }
    vector<int> ansx[2];
    f = false;
    for (auto &[x,y] : mp[1])
    {
        if (mp[3].count(X - x)) 
        {
            //reverse(y.begin(), y.end());
            ansx[0].insert(ansx[0].end(), y.begin(), y.end());
            //reverse(mp[3][X - x].begin(), mp[3][X - x].end());
            ansx[1].insert(ansx[1].end(), mp[3][X - x].begin(), mp[3][X - x].end());
            f = true;
            break;
        } 
    }
    if (!f) 
    {
        cout << "No\n";
        return ;
    }
    cout << "Yes\n";
    int last = 1;
    for (int i = 0; i < n; i++)
    {
        if (i % 2 == 0)
        {
            int j = i / 2;
            int now = j / 2;
            if (last == 1)
            {
                if (ansy[j % 2][now] == 1) cout << "L";
                else cout << "R";
            }
            else
            {
                if (ansy[j % 2][now] == 1) cout << "R";
                else cout << "L";
            }
            last = ansy[j % 2][now];
        }
        else
        {
            int j = i / 2;
            int now = j / 2;
            if (last == 1)
            {
                if (ansx[j % 2][now] == 1) cout << "R";
                else cout << "L";
            }
            else
            {
                if (ansx[j % 2][now] == 1) cout << "L";
                else cout << "R";
            }
            last = ansx[j % 2][now];
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    //cin >> t;
    while (t--)
        solve();
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nov-JovR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值