IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Educational Codeforces Round 115 (Rated for Div. 2)题解A-F -> 正文阅读

[数据结构与算法]Educational Codeforces Round 115 (Rated for Div. 2)题解A-F

Educational Codeforces Round 115 (Rated for Div. 2)

A. Computer Game

分析:

输出YES当且仅当,每一列都至少存在一个0.

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
using namespace std;
#define close(); 	ios::sync_with_stdio(false);
#define endl "\n"
#define sf scanf
#define pf printf
#define qf(i, l, r) for(int i = l; i <= r; i++)
#define qdf(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 3e5+100;
int dp[N];
char mp[2][N];
void solve()
{
    int n; scanf("%d",&n);
    scanf("%s %s",&mp[0][1],&mp[1][1]);
    dp[1] = 1;
    qf(i, 2, n) 
    {
        if((mp[0][i] == '0' || mp[1][i] == '0') && dp[i-1] == 1) dp[i] = 1;
        else dp[i] = 0;
    }
    if(dp[n]) printf("YES\n");
    else printf("NO\n");
}

int main()
{
    int T; scanf("%d",&T);
    while(T--) solve();
    // system("pause");
}

B. Groups

分析:

暴力枚举选取的两天, 然后检查是否可行即可.

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
using namespace std;
#define close(); 	ios::sync_with_stdio(false);
#define endl "\n"
#define sf scanf
#define pf printf
#define qf(i, l, r) for(int i = l; i <= r; i++)
#define qdf(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 3e5+100;
int dp[N];
char a[N][6];
void solve()
{
    int n; scanf("%d",&n);
    qf(i, 1, n) qf(j, 1, 5) sf("%d",&a[i][j]);
    bool f = 0;
    qf(i, 1, 5)
    {
        qf(j, i+1, 5) 
        {
            int x, y, z, d; x = y = z = d = 0;
            qf(k, 1, n)
            {
                if(a[k][i] == 1 && a[k][j] == 0) x++;
                else if(a[k][i] == 0 && a[k][j] == 1) y++;
                else if(a[k][i] == 1 && a[k][j] == 1) z++;
                else d++;
            }
            if(d != 0) continue;
            // pf("%d, %d: %d %d %d\n",i,j,x,y,z);
            if( x <= n/2 && y <= n/2 ) f = 1;
        }
    }
    if(f) pf("YES\n");
    else pf("NO\n");
}

int main()
{
    int T; scanf("%d",&T);
    while(T--) solve();
    // system("pause");
}

C. Delete Two Elements

分析:

不妨设数组和为sum.

不难将问题转化为 求数组a中有多少有序对 < i , j > <i,j> <i,j>使得 a i + a j = = s u m ? 2 / n a_i+a_j==sum*2/n ai?+aj?==sum?2/n

上map即可.

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
using namespace std;
#define close(); 	ios::sync_with_stdio(false);
#define endl "\n"
#define sf scanf
#define pf printf
#define qf(i, l, r) for(int i = l; i <= r; i++)
#define qdf(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 3e5+100;
map<int, int> mp;
void solve()
{
    mp.clear();
    int n; scanf("%d",&n);
    LL sum = 0;
    qf(i, 1, n) 
    {
        int ai;
        sf("%d",&ai);
        sum += ai;
        if(mp.find(ai) == mp.end()) mp[ai] = 1;
        else mp[ai]++;
    }
    int k = sum * 2 / n;
    if( sum * 2 % n != 0 ) { pf("0\n"); return; }
    LL ans = 0;
    for( auto p = mp.begin(); p != mp.end(); p++ )
    {
        if(mp.find(k-p->first) == mp.end()) continue;
        if(k - p->first == p->first)
        {
            ans += (p->second) * (LL)(p->second - 1);
        }
        else
        {
            ans += p->second * (LL)(mp.find(k-p->first)->second);
        }
    }
    pf("%lld\n",ans/2);
}

int main()
{
    int T; scanf("%d",&T);
    while(T--) solve();
    // system("pause");
}

D. Training Session

分析:

求至少符合题中所给两条件之一的情况的个数很难.

不妨求都不符合题中所给两条件的情况的个数, 再拿总的个数去减, 即可出答案.

观察
a a x y b b \begin{matrix} a & a & x \\ y & b & b \end{matrix} ay?ab?xb?
不难发现, 不符合题中所给两条件的情况必为上式所给形式.

map瞎搞一下即可.

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
using namespace std;
#define close(); 	ios::sync_with_stdio(false);
#define endl "\n"
#define sf scanf
#define pf printf
#define qf(i, l, r) for(int i = l; i <= r; i++)
#define qdf(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 3e5+100;
vector<int> T[N], D[N];
void solve()
{
    LL n; sf("%lld",&n);
    qf(i, 1, n) { T[i].clear(); D[i].clear(); }
    LL sum = n*(n-1)*(n-2)/6;
    qf(i, 1, n)
    {
        int t, d; sf("%d %d",&t,&d);
        T[t].push_back(d);
        D[d].push_back(t);
    }
    LL p2 = 0;
    qf(i, 1, n)
    {
        for(int e: T[i])
        {
            p2 += (LL)(D[e].size() - 1) * (LL)(T[i].size() - 1);
        }
    }
    pf("%lld\n",sum-p2);
}

int main()
{
    int T; scanf("%d",&T);
    while(T--) solve();
    // system("pause");
}

E. Staircases

分析:

不难发现每次翻转一个方块, 受影响的方块有 [ 1 , 3 n ? 2 ] [1, 3n-2] [1,3n?2]个.

d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0] 表示以方块ij结尾的1型阶梯的个数, d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1] 表示以方块ij结尾的2型阶梯的个数.

先dp一遍, 把所有方块的状态都算出来, 再对于每个询问暴力更新即可.

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
using namespace std;
#define close(); 	ios::sync_with_stdio(false);
#define endl "\n"
#define sf scanf
#define pf printf
#define qf(i, l, r) for(int i = l; i <= r; i++)
#define qdf(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 1024;
LL n, m, q; 
LL sum = 0;
LL f[N][N][2];

void show()
{
    qf(i, 1, n)
    {
        qf(j, 1, m)
        pf("%lld ",f[i][j][0]+f[i][j][1]-1);
        pf("\n");
    }
}

void solve()
{
    int x, y; sf("%d %d",&x,&y);
    if(f[x][y][0])
    {
        LL t = f[x][y][0], s = f[x][y][1];
        f[x][y][0] = f[x][y][1] = 0;
        sum -= s+t-1;
        for(int i = x, j = y+1, k = 1; i <= n && j <= m; k++)
        {
            if(k&1 && f[i][j][1]) f[i][j][1] -= t;
            else if(!(k&1) && f[i][j][0]) f[i][j][0] -= t;
            else break;
            sum -= t;
            if(k&1) i++;
            else j++;
        }
        for(int i = x+1, j = y, k = 1; i <= n && j <= m; k++)
        {
            if( k&1 && f[i][j][0]) f[i][j][0] -= s; 
            else if(!(k&1) && f[i][j][1]) f[i][j][1] -= s;
            else break;
            sum -= s;
            if(k&1) j++;
            else i++;
        }
    }
    else
    {
        LL t = f[x-1][y][1] + 1;
        LL s = f[x][y-1][0] + 1;
        f[x][y][0] = t;
        f[x][y][1] = s;
        sum += s+t-1;
        for(int i = x, j = y+1, k = 1; i <= n && j <= m; k++)
        {
            if(k&1 && f[i][j][1]) f[i][j][1] += t;
            else if(!(k&1) && f[i][j][0]) f[i][j][0] += t; 
            else break;
            sum += t;
            if(k&1) i++;
            else j++;
        }
        for(int i = x+1, j = y, k = 1; i <= n && j <= m; k++)
        {
            if(k&1 && f[i][j][0]) f[i][j][0] += s; 
            else if(!(k&1) && f[i][j][1]) f[i][j][1] += s;
            else break;
            sum += s;
            if(k & 1) j++;
            else i++;
        }
    }
    printf("%lld\n",sum);
    // show();
}

int main()
{
    sf("%lld %lld %lld",&n,&m,&q);
    sum = 0;
    qf(i, 1, n) qf(j, 1, m) 
    {
        f[i][j][0] = f[i-1][j][1] + 1;
        f[i][j][1] = f[i][j-1][0] + 1;
        sum += f[i][j][0] + f[i][j][1] - 1;
    }
    // cout << sum << endl;
    while(q--) solve();
    // system("pause");
}

F. RBS

分析:

考虑dp.

d p [ t ] dp[t] dp[t]为以t为压缩状态(即, t的第i位是否为1表示第i个字符串有没有被使用), 所有包含在t状态的字符串收尾相连 ,最多的RBS前缀个数.

显然 d p [ 0 ] = 0 dp[0] = 0 dp[0]=0

δ [ i ] \delta[i] δ[i] 为第i个字符串的左括号数减去右括号数.

m i n _ δ [ i ] min\_\delta[i] min_δ[i] 为第i个字符串中所有前缀中最小的 左括号数减去右括号数.

a [ i ] [ j ] a[i][j] a[i][j] 为第i个字符串的所有( (左括号数-右括号数) = j ) 的前缀的编号集合.

关于前缀的编号, 不妨以其结束的字符的下标做为其编号.

考虑我们dp到状态 t t t时, 记集合 T T T表示状态t所使用的字符串, d i f dif dif表示集合T所有字符串的左括号数减右括号数的和.

值得注意的是, 我们对dp[t]的定义是, 使用在集合T中所有的字符串按照任意可能的顺序相连, 最多的RBS前缀的个数.

特别的, 我们要使用dp[t]去更新下一个状态, 所以dp[t]所代表的相连字符串应该符合 任意前缀的左括号数减右括号数不小于0.

否则, 无论在状态t所代表的字符串添加任何字符串都无法更新答案.

因此, 我们拿一个不属于集合 T T T的字符串 s i s_i si?去尝试更新状态t的后继时, 有两种情况:

  1. 新构造的相连字符串依然符合 任意前缀的左括号数减右括号数不小于0 的性质, 那么更新状态 d p [ t ∣ 2 i ] dp[t|2^i] dp[t2i]
  2. 新构造的相连字符串不符合上述性质, 那么 d p [ t ] + s i 的 贡 献 dp[t]+s_i的贡献 dp[t]+si?是一种可行答案, 更新答案, 但不更新状态.

也就是说我们从状态 t = 0 t= 0 t=0开始dp, 最后中途算出的答案和 d p [ 2 n ? 1 ] dp[2^n-1] dp[2n?1]中的最大者为最终答案.

用数学归纳法不难证明上述每一步的正确性.

算法复杂度为 O ( m + 2 n n l o g m ) O(m+2^nnlogm) O(m+2nnlogm), 其中 m = ∑ l e n ( s i ) m = \sum len(s_i) m=len(si?)

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#include <assert.h>
using namespace std;
#define close(); 	ios::sync_with_stdio(false);
#define endl "\n"
#define qf(i, l, r) for(int i = l; i <= r; i++)
#define qdf(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 3e5+100;
int main()
{
    int n; cin >> n;
    vector<string> s(n);
    vector<vector<vector<int>>> a(n);
    vector<int> del(n);
    vector<int> min_del(n);

    qf(i, 0, n-1) 
    {
        cin >> s[i];
        int len = s[i].size();
        int x = len;
        a[i].resize(len*2+1);
        qf(j, 0, len-1)
        {
            x += (s[i][j]=='('?1:-1);
            a[i][x].push_back(j+1);
            min_del[i] = min(min_del[i], x-len);
        }
        del[i] = x-len;
    }
    vector<int> dp(1<<n, -1);
    dp[0] = 0;
    int ans = 0;
    qf(t, 0, (1<<n)-1)
    {
        if(dp[t] == -1) continue;
        int dif = 0;
        qf(i, 0, n-1) if(t & (1<<i)) dif += del[i];
        qf(i, 0, n-1)
        {
            if(t & (1<<i)) continue;
            int x = s[i].size() - dif;
            int now = dp[t];
            
            if(dif + min_del[i] < 0)
            {
                int val = a[i][x-1][0];
                now += (int)(lower_bound(a[i][x].begin(), a[i][x].end(), val) - a[i][x].begin());
                ans = max(ans, now);
                continue;
            }
            if(x >= 0 && x <= 2* s[i].size())
            now += a[i][x].size();
            dp[t | (1<<i)] = max(dp[t | (1<<i)], now);
            ans = max(ans, dp[t | (1<<i)]);
        }
    }
    cout << ans << endl;
    // system("pause");
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-12 23:43:35  更:2021-10-12 23:44:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:31:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码