Codeforces Round #556 (Div. 1)
Codeforces Round #556 (Div. 1)
A. Prefix Sum Primes
给你一堆1,2,你可以任意排序,要求你输出的数列的前缀和中质数个数最大。
发现只有\(2\)是偶质数,那么我们先放一个\(2\),再放一个\(1\),接下来把\(2\)全部放掉再把\(1\)全部放掉就行了。
#include<iostream>
#include<cstdio>
using namespace std;
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,a[3];
int main()
{
n=read();
for(int i=1;i<=n;++i)a[read()]+=1;
if(a[2])
{
printf("2 "),a[2]-=1;
if(a[1])printf("1 "),a[1]-=1;
}
while(a[2])printf("2 "),a[2]-=1;
while(a[1])printf("1 "),a[1]-=1;
puts("");
return 0;
}
B. Three Religions
给你一个串\(S\),会动态的修改三个串,修改是在三个串的末尾删去或加入一个字符。
每次修改完之后回答这三个串能否表示成\(S\)的三个不交的子序列。
考虑一个\(dp\),\(f[i][a][b][c]\),表示当前考虑到了串的第\(i\)个位置,匹配了到了三个串的\(a,b,c\)位置。
然后发现第一维这个东西非常蠢。把状态改一下,变成\(f[a][b][c]\)表示三个串分别匹配到\(a,b,c\)时\(i\)的最小值。
这样子单次修改转移的复杂度就是\(O(len^2)\),这样子复杂度就很对了。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
int n,Q;
int nxt[MAX][26],lst[26];
char s[MAX],a[4][MAX];
int len[4],f[255][255][255];
void dp(int x,int y,int z)
{
if(!(x|y|z))return;f[x][y][z]=n+1;
if(x&&f[x-1][y][z]<=n)f[x][y][z]=min(f[x][y][z],nxt[f[x-1][y][z]][a[1][x]-97]);
if(y&&f[x][y-1][z]<=n)f[x][y][z]=min(f[x][y][z],nxt[f[x][y-1][z]][a[2][y]-97]);
if(z&&f[x][y][z-1]<=n)f[x][y][z]=min(f[x][y][z],nxt[f[x][y][z-1]][a[3][z]-97]);
}
int main()
{
scanf("%d%d%s",&n,&Q,s+1);
for(int i=0;i<26;++i)lst[i]=n+1;
for(int i=n;~i;--i)
{
for(int j=0;j<26;++j)nxt[i][j]=lst[j];
if(i)lst[s[i]-97]=i;
}
while(Q--)
{
char ch[2],ss[2];int x;
scanf("%s%d",ch,&x);
if(ch[0]=='+')
{
scanf("%s",ss);
a[x][++len[x]]=ss[0];
if(x==1)
for(int i=0;i<=len[2];++i)
for(int j=0;j<=len[3];++j)
dp(len[1],i,j);
if(x==2)
for(int i=0;i<=len[1];++i)
for(int j=0;j<=len[3];++j)
dp(i,len[2],j);
if(x==3)
for(int i=0;i<=len[1];++i)
for(int j=0;j<=len[2];++j)
dp(i,j,len[3]);
}
else --len[x];
if(f[len[1]][len[2]][len[3]]<=n)puts("YES");else puts("NO");
}
return 0;
}
C. Tree Generator™
给你一个括号序列,显然一个合法的括号序列和一棵树是对应的。
现在每次交换括号序列的两个位置,求交换完之后的每一棵树的直径。
首先问题可以变成给定把(
看成\(1\),把)
看成\(-1\)。
于是问题就变成了你要在括号序列上找到任意一段连续的子串,并且把它分成两段,使得后一半的值减去前一半的值最大。
然后线段树维护一下就行了。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 200200
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,Q;char s[MAX];
struct Node{int pre[2],suf[2],ans,sum,tot;}t[MAX<<2],L,R;
Node operator+(Node a,Node b)
{
Node c;
c.pre[0]=max(a.pre[0],a.sum+b.pre[0]);
c.pre[1]=max(a.pre[1],max(a.tot+b.pre[0],-a.sum+b.pre[1]));
c.suf[0]=max(b.suf[0],-b.sum+a.suf[0]);
c.suf[1]=max(b.suf[1],max(b.tot+a.suf[0],b.sum+a.suf[1]));
c.sum=a.sum+b.sum;
c.tot=max(a.tot+b.sum,-a.sum+b.tot);
c.ans=max(max(a.ans,b.ans),max(a.suf[0]+b.pre[1],a.suf[1]+b.pre[0]));
return c;
}
void Modify(int now,int l,int r,int p)
{
if(l==r){t[now]=(s[p]=='(')?L:R;return;}
int mid=(l+r)>>1;
if(p<=mid)Modify(lson,l,mid,p);
else Modify(rson,mid+1,r,p);
t[now]=t[lson]+t[rson];
}
int main()
{
L=(Node){1,1,0,1,1,1,1};R=(Node){0,1,1,1,1,-1,1};
n=(read()-1)<<1;Q=read();scanf("%s",s+1);
for(int i=1;i<=n;++i)Modify(1,1,n,i);
printf("%d\n",t[1].ans);
while(Q--)
{
int x,y;swap(s[x=read()],s[y=read()]);
Modify(1,1,n,x);Modify(1,1,n,y);
printf("%d\n",t[1].ans);
}
return 0;
}
D. Abandoning Roads
你有一张图,你需要对于每一个点回答在任意一棵最小生成树中,\(1\)号点到这个点的路径的最小值是多少。
边权只有两种。
首先小的边权叫做\(a\),大的边权叫做\(b\)。
现在是\(a\)边构成了一堆联通块,然后你用\(b\)边把这些联通块链接然后求最短路。
这里直接求最短路有一个问题就是你不能在同一个联通块内用\(b\)边,也不能让一条路径重复的经过两次同一个联通块。
那么我们考虑状压,记录已经访问过了哪一些联通块。
然而这样子是\(2^n\)的。
发现大小为\(1,2,3\)的联通块你不可能用\(b\)边绕一圈再重新进来,所以只需要考虑大小至少为\(4\)的联通块。这样子复杂度就降下来了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAX 72
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next,w;}e[500];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int f[MAX],sz[MAX];
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
void Merge(int x,int y){x=getf(x);y=getf(y);f[y]=x;sz[x]+=sz[y];}
int dis[MAX][131072];bool vis[MAX][131072];
struct Node{int u,d,S;};
bool operator<(Node a,Node b){return a.d>b.d;}
priority_queue<Node> Q;
void upd(int u,int d,int S){if(dis[u][S]>d)dis[u][S]=d,Q.push((Node){u,d,S});}
int n,m,A,B,book[MAX],tim;
int main()
{
n=read();m=read();A=read();B=read();
for(int i=1;i<=n;++i)f[i]=i,sz[i]=1,book[i]=-1;
for(int i=1;i<=m;++i)
{
int u=read(),v=read(),w=read();
Add(u,v,w);Add(v,u,w);
if(w==A)Merge(u,v);
}
for(int i=1;i<=n;++i)
if(book[i]==-1&&sz[getf(i)]>3)
{
for(int j=i;j<=n;++j)
if(getf(i)==getf(j))
book[j]=tim;
++tim;
}
memset(dis,63,sizeof(dis));
upd(1,0,(~book[1])?1<<book[1]:0);
while(!Q.empty())
{
int u=Q.top().u,S=Q.top().S;Q.pop();
if(vis[u][S])continue;vis[u][S]=true;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v,w=e[i].w;
if(w==A)upd(v,dis[u][S]+w,S);
else
{
if(getf(u)==getf(v))continue;
if(~book[v]&&(S&(1<<book[v])))continue;
upd(v,dis[u][S]+w,S|((~book[v])?1<<book[v]:0));
}
}
}
for(int i=1;i<=n;++i)
{
int ans=1<<30;
for(int j=0;j<1<<tim;++j)ans=min(ans,dis[i][j]);
printf("%d ",ans);
}
return 0;
}
E. Election Promises
有一个\(DAG\),现在两个人轮流操作。每次操作可以随意指定一个权值不为\(0\)的点,然后把它的权值减小为任意非负整数,同时可以把其所有出边的点权任意修改。不能操作者输。
求先手是否必胜。
首先盲猜肯定和\(sg\)函数那套理论相关,然后把每个点的\(sg\)值给求出来。
题目的结论是:对于所有\(sg=i\)的点,我们令\(s_k=\oplus_{sg[i]=k}h[i]\),如果存在一个\(s_k\neq 0\)的话那么先手必胜,否则先手必败。
证明(伪证)
首先\(h\)全是\(0\)的时候一定是先手必败。
对于一个\(sg=k\)的点\(u\),其儿子中必定包含了\([0,k-1]\)这些\(sg\)值。那么我们找到最大的\(sg\)值,其一定只能影响所有比他小的\(sg\)值的位置。
那么我们修改这个\(sg\)值中\(h\)最大的那个点,那么必定可以让它的\(sg\)值减小,然后一定可以把所有的\(s\)全部变成\(0\),于是我们变成了一个必败态。
而后手此时操作完之后又一定存在至少一个数是\(0\),又成了必胜态。
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define MAX 200200
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
vector<int> E[MAX];
int n,m,h[MAX],sg[MAX],sum[MAX];
int dg[MAX],Q[MAX],vis[MAX];
void Topsort()
{
int h=1,t=0;
for(int i=1;i<=n;++i)if(!dg[i])Q[++t]=i;
while(h<=t){int u=Q[h++];for(int v:E[u])if(!--dg[v])Q[++t]=v;}
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)h[i]=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
E[u].push_back(v);
++dg[v];
}
Topsort();
for(int i=n;i;--i)
{
int u=Q[i];
for(int v:E[u])vis[sg[v]]=i;
while(vis[sg[u]]==i)++sg[u];
sum[sg[u]]^=h[u];
}
for(int i=n;~i;--i)
if(sum[i])
{
int pos;
for(int j=1;j<=n;++j)
if(sg[j]==i&&h[j]>(sum[i]^h[j]))pos=j;
h[pos]^=sum[i];
for(int v:E[pos])h[v]^=sum[sg[v]],sum[sg[v]]=0;
puts("WIN");
for(int j=1;j<=n;++j)printf("%d ",h[j]);
puts("");return 0;
}
puts("LOSE");
return 0;
}
Codeforces Round #556 (Div. 1)的更多相关文章
- Codeforces Round #556 (Div. 2) - C. Prefix Sum Primes(思维)
Problem Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Descripti ...
- Codeforces Round #556 (Div. 2) - D. Three Religions(动态规划)
Problem Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 3000 mSec Problem Descripti ...
- Codeforces Round #556 (Div. 2)
比赛链接 A 贪心 #include <cstdlib> #include <cstdio> #include <algorithm> #include <c ...
- Codeforces Round #556 (Div. 2) D. Three Religions 题解 动态规划
题目链接:http://codeforces.com/contest/1150/problem/D 题目大意: 你有一个参考串 s 和三个装载字符串的容器 vec[0..2] ,然后还有 q 次操作, ...
- Codeforces Round #556 (Div. 2)-ABC(这次的题前三题真心水)
A. Stock Arbitraging 直接上代码: #include<cstdio> #include<cstring> #include<iostream> ...
- Codeforces Round #556 题解
Codeforces Round #556 题解 Div.2 A Stock Arbitraging 傻逼题 Div.2 B Tiling Challenge 傻逼题 Div.1 A Prefix S ...
- Codeforces Round #366 (Div. 2) ABC
Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...
- Codeforces Round #354 (Div. 2) ABCD
Codeforces Round #354 (Div. 2) Problems # Name A Nicholas and Permutation standard input/out ...
- Codeforces Round #368 (Div. 2)
直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...
随机推荐
- GSOAP服务卡住?
很久以前参考了https://www.genivia.com/doc/soapdoc2.html 中的一段: How to Create a Multi-Threaded Stand-Alone Se ...
- Javascript 关于基本类型和引用类型的个人理解
一.基础类型 A. 基础类型有5种,Number,String,Boolean,Null,Undefined B. 基础类型没有堆的概念,堆只针对引用类型. 所有基础类型都是以key-value形式存 ...
- Linux 和 Windows多线程函数对应表
Linux Pthread API Windows SDK 库对应 API 创建 pthread_create CreateThread 退出 pthread_exit ThreadExit 等待 p ...
- 个人项目wc(Java)
个人项目(Java) 一丶Github地址:https://github.com/SAH2019/S ...
- 网络唤醒(WOL)全解指南:原理篇【转】
转自:https://blog.csdn.net/z5859095/article/details/82819075 什么是网络唤醒网络唤醒(Wake-on-LAN,WOL)是一种计算机局域网唤醒技术 ...
- Python环境安装与基础语法(1)——计算机基础知识
Python安装 pip #包管理工具 pip install #安装包 pip list #查看包 IPython #增强的python shell,自动补全,自动缩进,支持shell,增加了很多函 ...
- 201871010110-李华《面向对象程序设计(java)》第十五周学习总结
博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...
- Mac环境下 jieba 配置记录
在终端里输入: pip3 install jieba -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
- Vs2012安装介绍
1.下载Vs2012旗舰版安装文件 http://download.microsoft.com/download/B/0/F/B0F589ED-F1B7-478C-849A-02C8395D0995/ ...
- 莫烦TensorFlow_08 tensorboard可视化进阶
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt # # add layer # def add_l ...