A 送分 拼手速
快速读懂题意后
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int a,b,c;
cin>>a>>b>>c;
int d = abs(a-b);
int x = min(a,b);
int y = max(a,b);
int ans;
if(c<=d)//双手人少于两种人的差
ans = x+c;
else
ans = y+(c-d)/2;
cout<<2*ans<<endl;
}
B 基本送分,也拼手速
双指针比较,老是因为i和j的自增写错,
记住一点,i,j是指向当前值,还是之后的值,
我这里i,j都是指向当前值,即用到在自增;
这样不容易出错
#include <iostream>
#include <cmath>
using namespace std;
const int N=1e5+10;
int A[N];
int B[N];
int n,m;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)cin>>A[i];
for(int j=0;j<m;j++)cin>>B[j];
int i,j;
i=j=0;
int s1,s2;
s1=A[i];
s2=B[j];
int ans=0;
while(i<n && j<m)
{
if(s1==s2)
{
ans++;
i++;j++;
s1=A[i];
s2=B[j];
}
else if(s1<s2)
{
i++;
s1+=A[i];
}
else
{
j++;
s2+=B[j];
}
}
if(i!=n||j!=m)//跳出循环再判断是否要+1
{
ans++;
}
cout<<ans<<endl;
}
C 思路挺简单的一道题,代码不是很好写罢了
- Zabre 469 div2 C
比赛的时候没看清楚题目,单个的0,和00 都是合法的,所以末尾剩下的0就不用考虑匹配了,这样就很简单
只要考虑1,充分利用现有的0,把1都给放了,(按照题意0101的规则放置)
这样考虑,输出-1的情况只有两个
- 没有0来放后面的1
- 最后放完了还有1在最后面
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <list>
#include <queue>
/*
#include <cmath>
#include <cstdlib>
#include <algorithm>
*/
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
const int N=2e5+10;
int queue_tail[N];//保存每一个子序列的尾部
vector<int> T[N];//保存子序列的下标
int main()
{
string s;
cin>>s;
int len=0;
queue<int> zero,one;//暴力搜索能放的位置会TLE,把能放的位置放在队列里
int top=0;//每个多出来的0都放在top位置,以便继续放后面的1;
bool fg=true;
mem(queue_tail);
for(int i=0;i<s.length();i++)
{
char tp = s[i];
if(tp=='0')
{
int loc;
if(zero.empty())
{
loc=top++;
}
else
{
loc = zero.front();
zero.pop();
}
T[loc].push_back(i+1);
queue_tail[loc]=0;
one.push(loc);
}
else
{
int loc;
if(one.empty())
{
fg=false;
break;
}
else
{
loc = one.front();
one.pop();
}
T[loc].push_back(i+1);
queue_tail[loc]=1;
zero.push(loc);
}
}
for(int i=0;i<top;i++)
{
if(queue_tail[i]==1)
{
fg=false;
break;
}
}
if(fg)
{
int i=0;
printf("%d\n",top);
int len;
while(true)
{
len = T[i].size();
if(len==0)break;
printf("%d ",len);
for(int j=0;j<len;j++)
{
printf("%d%s",T[i][j],j==len-1?"\n":" ");
}
i++;
}
}
else
{
cout<<-1<<endl;
}
return 0;
}
E. Data Center Maintenance
题意:
题目很长读了半天,就是几个个东西
- 有n个数据中心
- 有m个客户
- 每天有h小时
- 数据中心在某几个小时点会进行一小时的维护
- 每个客户能从两个不同的数据中心获取数据
- 问题的前提是任一客户在任意时间都至少有一个数据中心不在维护
- 问题的输出就是,关键 在保证6的情况下,取一个最小子集,将他们延后一个小时
- 试想,如果原来满足6,那么把所有维护机都往后延后一个小时,还是能保证6,所以每个问题都至少有一个解,就是全部拿来实验
尝试解题
数据n,m,h的范围都是1e5;
nlogn的复杂度才能保证不TLE
对于第二个样例(我们吧数据中心的下标列在客户数据后面)
4 5 4
2 1 0 3
4 3 0 3
3 2 0 1
1 2 2 1
1 4 2 3
1 3 2 0
不难看出来,如果一个客户的两个客户中心相差一个小时,那早更新的那个如果加入实验,必然导致另外一个也加入实验,对于一个二元关系我们可以建立一个图来解决
例如第2个客户,3 2
那么数据中心3连一条有向弧到2;表示,如果数据中心3,如果加入试验,那么2也必须加入试验。
那么问题就转换成为
求一个最小的连通块
接下来代码就很好写了
写着发现没这么简单
应该要先将这个有向图缩点 成为一个DAG
然后 取 缩点后的所有出度为0的点 中 点的数目最小的那个连通块,才能满足题意。
缩点代码参考我的另外一篇blog
本题代码
比赛当时实在不想看题目,
第二天也花了好长时间才看懂题目。虽然结合样例不难看懂,但是还是看了好长时间。
看懂题目了的话思路就很清晰,既然是一个二元约束关系,转换成图论来写就行了。
然后第一发WA了,坑点是,建图的时候,如果只有两个数据中心,并且时间分别是,0和1
那么对于一个客户01来说可以牵两条边即 0->1 ,1->0;
我写的时候没注意,如果真真的比赛,我想很难发现这个问题吧。
谁能想到是建图建错了。。。。
抽象一下就是,对于一个客户来讲,可能产生两个约束关系;
值得一提的是,这里n比较大。所以不能用邻接矩阵来去掉重复边。
不过好在,m对边的限制,不会让复杂度爆炸,依旧用vector数组的邻接表来表示图;
tarjan算法要记录每个强连通分量的number,以及每个点所属的连通分量。
在缩点和,最后输出那个scc的所有的点的时候要用到。
#include <cstring>
#include <cstdio>
#include <vector>
#include <iostream>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
int n,m,h;
const int N=1e5+10;
int A[N];
int ans[N];
int k;
int Low[N],DFN[N],Stack[N],Belong[N];
int Index,top;
int scc;
bool Instack[N];
int num[N];
int outdegree[N];
vector<int> G[N];
void init()
{
for(int i=1;i<=n;i++)
G[i].clear();
mem(outdegree);
}
void Tanjan(int u)
{
int v;
Low[u]= DFN[u] =++Index;
Stack[top++]=u;
Instack[u]=true;
for(int i=0;i<G[u].size();i++)
{
v=G[u][i];
if(!DFN[v])
{
Tanjan(v);
if(Low[u]>Low[v])Low[u]=Low[v];
}
else if(Instack[v] && Low[u]>DFN[v])
Low[u]=DFN[v];
}
if(Low[u]==DFN[u])
{
scc++;
do
{
v=Stack[--top];
Instack[v]=false;
Belong[v]=scc;
num[scc]++;
}while(v!=u);
}
}
void solve(int n)
{
mem(DFN);
mem(Instack);
mem(num);
Index = scc = top = 0;
for(int i=1;i<=n;i++)
if(!DFN[i])
Tanjan(i);
}
int main()
{
//freopen("../in.txt","r",stdin);
while(cin>>n>>m>>h)
{
init();
for(int i=1;i<=n;i++)
cin>>A[i];
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
int aa,bb;
aa=A[a];
bb=A[b];
if((aa-bb)==1)
{
G[b].push_back(a);
}
else if((bb-aa)==1)
{
G[a].push_back(b);
}
if((aa-bb)==(h-1))
{
G[a].push_back(b);
}
else if((bb-aa)==(h-1))
{
G[b].push_back(a);
}
}
solve(n);
for(int u=1;u<=n;u++)
{
int v;
int uu,vv;
uu=Belong[u];
for(int j=0;j<G[u].size();j++)
{
v=G[u][j];
vv=Belong[v];
if(uu!=vv)
{
outdegree[uu]++;
}
}
}
int k,cnt;
cnt=n+1;
for(int i=1;i<=scc;i++)
{
if(outdegree[i]==0 && num[i]<cnt)
{
cnt=num[i];
k=i;
}
}
int tt=0;
for(int i=1;i<=n;i++)
if(Belong[i]==k)
ans[tt++]=i;
cout<<cnt<<endl;
for(int i=0;i<tt;i++)
cout<<ans[i]<<(i==tt-1?"\n":" ");
}
return 0;
}