Educational Codeforces Round 114 (Rated for Div. 2)题解
还是常规的过了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)题解的更多相关文章
- Educational Codeforces Round 63 (Rated for Div. 2) 题解
Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...
- Educational Codeforces Round 65 (Rated for Div. 2)题解
Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...
- Educational Codeforces Round 64 (Rated for Div. 2)题解
Educational Codeforces Round 64 (Rated for Div. 2)题解 题目链接 A. Inscribed Figures 水题,但是坑了很多人.需要注意以下就是正方 ...
- Educational Codeforces Round 60 (Rated for Div. 2) 题解
Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...
- Educational Codeforces Round 58 (Rated for Div. 2) 题解
Educational Codeforces Round 58 (Rated for Div. 2) 题目总链接:https://codeforces.com/contest/1101 A. Min ...
- Educational Codeforces Round 47 (Rated for Div. 2) 题解
题目链接:http://codeforces.com/contest/1009 A. Game Shopping 题目: 题意:有n件物品,你又m个钱包,每件物品的价格为ai,每个钱包里的前为bi.你 ...
- Educational Codeforces Round 93 (Rated for Div. 2)题解
A. Bad Triangle 题目:https://codeforces.com/contest/1398/problem/A 题解:一道计算几何题,只要观察数组的第1,2,n个,判断他们能否构成三 ...
- Educational Codeforces Round 33 (Rated for Div. 2) 题解
A.每个状态只有一种后续转移,判断每次转移是否都合法即可. #include <iostream> #include <cstdio> using namespace std; ...
- 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 ...
随机推荐
- 成本降低40%、资源利用率提高20%的 AI 应用产品云原生容器化之路
作者 郭云龙,腾讯云高级工程师,目前就职于 CSIG 云产品三部-AI 应用产品中心,现负责中心后台业务框架开发. 导语 为了满足 AI 能力在公有云 SaaS 场景下,服务和模型需要快速迭代交付的需 ...
- 一起学习PHP中GD库的使用(一)
又到了一个大家非常熟悉的库了,对于图像图形的处理来说,GD 库是 PHPer 们绕不过去的一道坎.从很早很早的 CMS 或者 Discuz 时代,各类开源软件在安装的时候就会明确地指出 GD 库是它们 ...
- php处理url的rawurlencode:可处理空格加号
(PHP 4, PHP 5, PHP 7) rawurlencode - 按照 RFC 3986 对 URL 进行编码 返回字符串,此字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号( ...
- symfony generate:bundle出现提示: Checking that the bundle is autoloaded
可以参考官方文档给出来的解决办法 http://symfonychina.com/doc/current/bundles/SensioGeneratorBundle/commands/generate ...
- SQL-关联查询【转】
T_A A表 T_B B标,id为表与表相关联的字段`创建相关表结构 CREATE TABLE Table_B( id INT(2), serNum VARCHAR(10) ); CREATE TAB ...
- 今天我抓了个 HTTPS 的包
之前写过一篇讲 HTTPS 的思想的文章. 破玩意 | 用 HTTPS 传纸条 后来又写了篇用更凝练的语言总体描述了 HTTPS 的主干. 叮咚 | HTTPS 的分支和主干 想必通过这两篇文章,HT ...
- Flawfinder在Python2和Python3环境下对代码进行扫描方法
1. Flawfinder Flawfinder是一款开源的关于C/C++静态扫描分析工具,其根据内部字典数据库进行静态搜索,匹配简单的缺陷与漏洞. 官网:https://dwheeler.com/f ...
- 数据库建表权限 CREATE command denied to user for table
今天在表中用Navicat连接服务器上的mysql账号进行建表,报了个这样类似的错, CREATE command denied to user for table 是数据库权限设置的问题,所以无法进 ...
- [RabbitMQ]下载&安装
RabbitMQ是基于Erlang语言开发的消息中间件,所以使用RabbitMQ需要安装Erlang和RabbitMQ两个软件. 1 Erlang 1.1 下载 官网下载地址:https://www. ...
- 关于 Spring Boot 中创建对象的疑虑 → @Bean 与 @Component 同时作用同一个类,会怎么样?
开心一刻 今天放学回家,气愤愤地找到我妈 我:妈,我们班同学都说我五官长得特别平 妈:你小时候爱趴着睡觉 我:你怎么不把我翻过来呢 妈:那你不是凌晨2点时候出生的吗 我:嗯,凌晨2点出生就爱趴着睡觉呗 ...