还是常规的过了A,B,C还是在D上卡了...

D. The Strongest Build

简化题意:给定你n组东西,每组东西都有\(c_i\)个装备,每个装备有一个武力值\(a_{i,j}\),要求你从每一组中选出一个装备,使得总的装备的武力值最大。但有一些给定的方案是不能选的。

首先看到这个题的第一印象是只有\(m\)中方案是不能选的。那我们直接从最大的方案开始,一点点的调整为次大的,第三大的,第四大的,....,最多也就调整m次。但发现这个调整真的太难了...实现不了。其实想一下,这个题总的方案数也就\(\prod c_i\)这么多。我们可以直接对其进行搜索。但直接搜索全部的方案显然不太现实,我们依据一下原则:

1:初始的策略就是先选每一组中的最大值。

2:若当前这个策略不合格,则将当前策略中的某一组,将它的装备降为下一级,形成一个新的策略。

3:对所有当前的策略,优先取出和最大的策略进行检查。若不合法,则按照2生成其他的策略,否则,直接退出当前值为最大值。

总的贪心的思路和dijkstra算法差不多,不过算法形式和应用范围相差却深远。

学习某个算法的形式真的解决不了太多问题,掌握了其真正的思路与核心才掌握了它的一切!

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,MN=15;
int n,m,c[MN],a[MN][N];
map<vector<int>,bool>mp;
map<vector<int>,bool>vis;
priority_queue<pair<int,vector<int> > >q;
int main()
{
// freopen("1.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&c[i]);
for(int j=1;j<=c[i];++j) scanf("%d",&a[i][j]);
}
vector<int>s;
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
for(int j=1;j<=n;++j)
{
int x;scanf("%d",&x);
s.push_back(x);
}
mp[s]=1;s.clear();
}
int s1=0;
for(int i=1;i<=n;++i) s.push_back(c[i]),s1+=a[i][c[i]];
vector<int>ans;q.push({s1,s});vis[s]=1;
while(!q.empty())
{
pair<int,vector<int> >x=q.top();q.pop();
if(mp.find(x.second)==mp.end()) {ans=x.second;break;}
for(int i=1;i<=n;++i)
{
if(x.second[i-1]>=2)
{
x.second[i-1]--;
if(vis.find(x.second)==vis.end())
{
q.push({x.first-a[i][x.second[i-1]+1]+a[i][x.second[i-1]],x.second});
vis[x.second]=1;
}
x.second[i-1]++;
}
}
}
for(auto x:ans) printf("%d ",x);
return 0;
}

E. Coloring

这个E题真的好难搞啊!!!

要被虐哭了都,题解翻译过来根本看不懂,只能一边看官方题解代码,一边试图理解题解里的话。

只能慢慢的整理思路....

首先遇到这种题不要慌!!!先尝试着随便写写,列举下,找找规律,这种题肯定是找到某种性质,然后根据性质做题。

这个题就直接说了,首先根据随便写写,随便推推可以发现一个重要的性质(这只能靠内力了):

如果有两个同一行格子相邻且数字相同的话,那么他们这两个格子所在的两列就唯一确定了。

例如如果(3,3)和(3,4)都为1,则(2,3)和(2,4)只能为0,(4,3)和(4,4)只能为0,(1,3)和(1,4)只能为1,(5,3)和(5,4)只能为0,....可以一直推下去,这两列就唯一确定了(我们成为列条带)。如果是同一列中两个相邻数字相同,则这两行也唯一确定(我们成为横条带),和上述类似。

那么我们知道了两个相邻格子的会使两列唯一确定。接下来考虑什么情况下会出现两个相邻格子数字相同的情况,稍微推一下就能得知:1.当同一行有两个格子数字相同且中间的格子个数为偶数,那么这之间一定会有两个相邻的格子数字相同。比如(3,3)和(3,6)两个格子都是1,不管(3,4)和(3,5)怎么填,都会有两个相邻的格子数字相同的情况出现。2.当同一行有两个格子数字不同且中间的格子数为奇数的话,那么这之间一定会有两个相邻的格子数字相同。刺入(3,3)为1,(3,5)为0,不管你咋填,都一定会有两个相邻的格子数字相同。

同时我们会发现若同时有横条带和列条带的话,那么这两种条带一定会冲突,因为你会发现列条带相邻行是不同的,而横条带却要求相邻行要相同。最简单的例子就是一个\(2\times2\)的格子,(1,1)和(1,2)都为1,那么根据列条带的话,则(2,1)和(2,2)也应该为0,但如果使(2,1)也为1则出现横条带两者冲突。

所以合法的局面是只能出现横条带或列条带,或不出现条带。

分开考虑:若不出现条带,即不能出现格子相邻且数字相同,发现这个一共就两种。0101010...和1010110全部错开就行。

列条带:我们考虑若有列条带的话,(即如果同一行有两个数字相同的格子他们中间的格子数为偶数(\(0\)也算偶数)),这两个列条带就不用考虑了,其他的列考虑相邻的行都不能相同(否则就会出现横条带),发现一列就只有两种情况,\(010101010....\)和\(1010101010...\)但如果这一列中有数字的话,那么这一列就从这两种情况中唯一确定了。设\(nx\)为没有数字的列,那么列的情况数就是\(2^{nx}\),横条带和列类似。同时我们发现我们如果有某一行出现产生列条带的条件,这两列也被唯一确定了,同时他们也因为相对应的列出现了数字而被唯一确定,他们对答案并不影响。换句话说我们根本没有必要去统计到底是哪些列出现了产生列条带的条件,我们只关注到底有没有哪一行出现产生列条带的条件,从而使得整个局面处于列条带的情况下。

那么我们怎么快速知道一行是否有相邻且数字相同的格子出现,我们发现这和格子的奇偶有关,我们只需要记录每行,每列格子中数字0/1处在奇数,偶数的位置的个数,结合这个和上面的两条判断条带出现的条件,当一个新的数来时,我们可以快速判断这一行这一列是否产生条带。

具体我们需要维护一下信息:

1.每个格子的颜色。(用map<pair<int,int>,int>解决。)

2.哪些行产生条带,哪些列产生条带了。支持动态删除和加入,统计数量。(用set解决。)

3.哪些行,列出现了数字。支持动态删除,加入,统计数量。(用set结局。)

这里的小细节就是有时候统计答案,可能会重复计算没有条带的情况。这里特判下即可。

最后代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10,P=998244353;
int n,m,k,cnth[N][2][2],cntl[N][2][2],cntx[2][2];
//cnth,cntl分别记录第i行/列数字0/1在奇数/偶数的位置上有多少个
//cntx这里是为了特判当横条带,列条带都没出现时,当前的数字能否确定出现没条带的情况。
ll p[N];//p预处理2的次幂
map<pair<int,int>,int>mp;//记录格子上的数字。
set<int>sh,sl;//记录哪些行/列能因此形成条带
set<int>uh,ul;//记录哪些行/列有数字
inline bool check(int cnt[2][2])//判断这个行/列是否能形成条带。
{
if(cnt[1][0]>0&&cnt[1][1]>0||cnt[0][0]>0&&cnt[0][1]>0) return true;
for(int i=0;i<=1;++i)
{
if(cnt[1][i]>0&&cnt[0][i]>0) return true;
}
return false;
}
inline void add(int x,int y,int t)//像某个格子添加数字
{
cnth[x][t][y&1]++;
cntl[y][t][x&1]++;
if(uh.find(x)==uh.end()) uh.insert(x);
if(ul.find(y)==ul.end()) ul.insert(y);
if(sh.find(x)==sh.end()&&check(cnth[x]))
sh.insert(x);
if(sl.find(y)==sl.end()&&check(cntl[y]))
sl.insert(y);
mp[{x,y}]=t;
cntx[t][(x&1)^(y&1)]++;
}
inline void upd(int x,int y,int t)
{
if(mp.find({x,y})!=mp.end())//先把这个格子的数删掉。
{
cntx[mp[{x,y}]][(x&1)^(y&1)]--;//先删除这个格子的影响,以及这个行,列所在的信息。
cnth[x][mp[{x,y}]][y&1]--;
cntl[y][mp[{x,y}]][x&1]--;
uh.erase(x);ul.erase(y);
if(sh.find(x)!=sh.end()) sh.erase(x);
if(sl.find(y)!=sl.end()) sl.erase(y);
mp.erase({x,y});
//以下重新统计该行该列的信息。
if(cnth[x][0][0]||cnth[x][0][1]||cnth[x][1][0]||cnth[x][1][1]) uh.insert(x);
if(cntl[y][0][0]||cntl[y][0][1]||cntl[y][1][0]||cntl[y][1][1]) ul.insert(y);
if(check(cnth[x])) sh.insert(x);
if(check(cntl[y])) sl.insert(y);
}
if(t==-1) return;
add(x,y,t);
return;
}
int main()
{
//freopen("1.in","r",stdin);
p[0]=1;
for(int i=1;i<=1e6;++i) p[i]=p[i-1]*2%P;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;++i)
{
int x,y,t;
scanf("%d%d%d",&x,&y,&t);
upd(x,y,t);
ll ans=0;
if(sh.size()>0&&sl.size()>0) ans=0;//即出现横条带也出现列条带,答案为0.
else if(sh.size()>0) ans=p[m-ul.size()];//只出现列条带,按照列条带的方式计算。
else if(sl.size()>0) ans=p[n-uh.size()];//只出现横条带。
else
{
if(ul.size()==0&&uh.size()==0) ans=(p[n]+p[m]-2+P)%P;//两个都没出现。
else
{
ans=(p[m-ul.size()]+p[n-uh.size()]+P)%P;
if(cntx[1][0]+cntx[0][1]==0||cntx[0][0]+cntx[1][1]==0) ans=(ans-1+P)%P;
}
}
printf("%lld\n",ans);
}
return 0;
}

不用尽全力,你永远不会知道自己的潜力有多大!

Educational Codeforces Round 114 (Rated for Div. 2)题解的更多相关文章

  1. Educational Codeforces Round 63 (Rated for Div. 2) 题解

    Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...

  2. Educational Codeforces Round 65 (Rated for Div. 2)题解

    Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...

  3. Educational Codeforces Round 64 (Rated for Div. 2)题解

    Educational Codeforces Round 64 (Rated for Div. 2)题解 题目链接 A. Inscribed Figures 水题,但是坑了很多人.需要注意以下就是正方 ...

  4. Educational Codeforces Round 60 (Rated for Div. 2) 题解

    Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...

  5. Educational Codeforces Round 58 (Rated for Div. 2) 题解

    Educational Codeforces Round 58 (Rated for Div. 2)  题目总链接:https://codeforces.com/contest/1101 A. Min ...

  6. Educational Codeforces Round 47 (Rated for Div. 2) 题解

    题目链接:http://codeforces.com/contest/1009 A. Game Shopping 题目: 题意:有n件物品,你又m个钱包,每件物品的价格为ai,每个钱包里的前为bi.你 ...

  7. Educational Codeforces Round 93 (Rated for Div. 2)题解

    A. Bad Triangle 题目:https://codeforces.com/contest/1398/problem/A 题解:一道计算几何题,只要观察数组的第1,2,n个,判断他们能否构成三 ...

  8. Educational Codeforces Round 33 (Rated for Div. 2) 题解

    A.每个状态只有一种后续转移,判断每次转移是否都合法即可. #include <iostream> #include <cstdio> using namespace std; ...

  9. Educational Codeforces Round 78 (Rated for Div. 2) 题解

    Shuffle Hashing A and B Berry Jam Segment Tree Tests for problem D Cards Shuffle Hashing \[ Time Lim ...

随机推荐

  1. Insecure CAPTCHA (不安全的验证码)

    dvwa不能正常显示,需要在配置文件中加入谷歌的密钥: $_DVWA[ 'recaptcha_public_key' ] = '6LfX8tQUAAAAAOqhpvS7-b4RQ_9GVQIh48dR ...

  2. Docker安装flink及避坑指南

    Docker安装flink 导航 无处不在的大数据 安装flink 拉取flink镜像 编写docker-compose.yml 生成启动 查看安装效果 常见坑及解决方案 问题1 问题2 参考   本 ...

  3. Java多线程-1(3)

    本份随记主要为狂神老师的Java多线程教学的学习笔记,记载了视频中一些有关基础概念以及部分代码示例.随机分为1-3共三份,知识点记录的不是很深入,以后的学习过程中随时补充. 1 有关基础概念 1.1 ...

  4. PHP中操作数据库的预处理语句

    今天这篇文章的内容其实也是非常基础的内容,不过在现代化的开发中,大家都使用框架,已经很少人会去自己封装或者经常写底层的数据库操作代码了.所以这回我们就来复习一下数据库中相关扩展中的预处理语句内容. 什 ...

  5. Django+Nginx+Uwsgi(全网最全步骤工作原理流程与部署历程)

    一.必要前提 1.1 准备知识 django 一个基于python的开源web框架,请确保自己熟悉它的框架目录结构. uWSGI 一个基于自有的uwsgi协议.wsgi协议和http服务协议的web网 ...

  6. 关于我的Visual Studio2017修改安装重试9次失败问题解决

    环境:windows vs2017 现象描述:本来我的vs可用的,一天想暗爪QT,插件安装好了不能创建QT项目,准备升级,然后问题出现了. 过程: 把人弄崩溃了,二三十k的速度在走,半路又终止.根本不 ...

  7. node二进制安装

    你可能因为重装系统node的npm不管用, 但是node管用, 我不知道为什么, 但是 二进制安装就好了 管他那么多 下面这些网址你就可以了 https://blog.csdn.net/wocaoni ...

  8. bzoj1341 名次排序问题rank sorting(dp,考虑到对未来的贡献)

    QWQ啊 这个题可以说是我目前碰到过的最难理解的dp之一了. 题目大意: 已知参赛选手的得分,你的任务是按照得分从高到底给出选手的排名.遗憾的是,保存选手信息的数据结构只支持 一种操作,即将一个选手从 ...

  9. 洛谷4719 【模板】动态dp 学习笔记(ddp 动态dp)

    qwq大概是混乱的一个题. 首先,还是从一个比较基础的想法开始想起. 如果每次暴力修改的话,那么每次就可以暴力树形dp 令\(dp[x][0/1]\)表示\(x\)的子树中,是否选择\(x\)这个点的 ...

  10. C#并行编程:Parallel的使用

    前言:在C#的System.Threading.Tasks 命名空间中有一个静态的并行类:Parallel,封装了Task的使用,对于执行大量任务提供了非常简便的操作.下面对他的使用进行介绍. 本篇内 ...