现在主要写div2的题,从前往后写到实在不会写,思路很简单的就不记录了
- E. Game with String
题意:两个人玩游戏,AB都知道原字符串s,A将s从下表为k的位置断开,左右交换组成新的字符穿t
B猜k,求b的赢得几率
B有两个手段
1.先看新字符串t的首字母也就是s[k+1]
2.看完首字母后 决定看t的任意一个字符
最后求B能百分百猜对t的概率
简单的博弈概率题目
图书馆要关了,先存档一下,明天再写
#include
#include
#include
#include
#include
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
const int N=5e3;
int n,len;
char str[N+10];
char ss[N+10];
bool have[26];
vector<string> arr[26];
void merge(char *s,int t)
{
int top=0;
for(int i=t;ifor(int i=0;i'\0';
}
int main()
{
while(~scanf("%s",str))
{
//init
mem(have);
for(int i=0;i<26;i++)arr[i].clear();
len=0;
//get len
for(int i=0;str[i]!='\0';i++)
{
len++;
have[str[i]-'a']=true;
}
//得到字符串矩阵
int top=0;//arr的下标
for(int i=0;i<26;i++)if(have[i])
{
char c='a'+i;
for(int j=0;jif(str[j]==c)
{
merge(ss,j);
printf("%s\n",ss);
arr[top].push_back(string(ss));
}
}
top++;
}
double ans = 0;
for(int i=0;iint len1 = arr[i].size();
int maxt=0;
for(int j=1;jint cnt[26];
mem(cnt);
int tt=0;
for(int k=0;kchar tp = arr[i][k][j]-'a';
cnt[tp]++;
}
for(int k=0;k<26;k++)if(cnt[k]==1)tt++;
maxt = max(maxt,tt);
}
ans+=(double)maxt;
}
double p = ans/len;
printf("%.14f\n",p);
}
return 0;
}
题意有点误会,所以写错了,在所有字符串排列成的矩阵中
比如
actactictict
actictictact
ctictactacti
ctactacticti
ctacticticta
ctictictacta
ictictactact
ictactactict
tictictactac
tictactactic
tactactictic
tactictictac
ac代码只要对所有行sigma(max(每一列的不重复出现的字母))/len(str)即可
感觉很坑,不是求猜正确的概率,
而是求,随机一个k,看一个首字母,存在能100%确定t的概率。
- Zabre 469 div2 C
比赛的时候没看清楚题目,单个的0,和00 都是合法的,所以末尾剩下的0就不用考虑匹配了,这样就很简单
只要考虑1,充分利用现有的0,把1都给放了,(按照题意0101的规则放置)
这样考虑,输出-1的情况只有两个
- 没有0来放后面的1
- 最后放完了还有1在最后面
#include
#include
#include
#include
#include
#include
/*
#include
#include
#include
*/
#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;ichar 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;iif(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;jprintf("%d%s",T[i][j],j==len-1?"\n":" ");
}
i++;
}
}
else
{
cout<<-1<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
本题代码