A - Daily Cookie (abc382 A)
题目大意
给定一个长度为N的字符串,有很多.
和@
,一共有D天,每天会使一个@
变成.
,问D天之后有几个.
解题思路
数一下有几个.
,答案会加D个.
。
代码
void solve()
{
int n, d;
string s;
cin >> n >> d >> s;
cout<<count(s.begin(),s.end(),'.')+d;
}
B - Daily Cookie 2 (abc382 B)
题目大意
题意和第一题差不多,但是每天会让最右边的@
变成.
,问D天之后的字符串长什么样。
解题思路
按照题意模拟即可。
代码
void solve()
{
int n, d;
string s;
cin >> n >> d >> s;
int cnt = 0;
for(int i=(int)s.size()-1;i>=0;i--){
if (s[i] == '@') {
cnt++;
s[i] = '.';
if (cnt == d) break;
}
}
cout << s;
}
C - Kaiten Sushi (abc382 C)
题目大意
题目意思很复杂,可以自己阅读一下,我这里简化题意。
给定一个长度为N的数组A,并且有M次查询B。
对于第i个查询Bi问A数组里从左往右第一个小于等于Bi的数的下标是多少
解题思路
题目是离线的,那么B数组的顺序无关紧要,把他压进一个优先队列里,然后从左向右遍历A数组,每次把所有大于等于Ai的数都弹出队列并且标记答案就可以了。
代码
#define rep(i,n) for(int i=0;i<n;i++)
priority_queue<pair<int,int> > q;
int a[200005],b[200005];
int ans[200005];
void solve()
{
int n, m;
cin >> n >> m;
rep(i,n) cin>>a[i];
rep(i,m) cin>>b[i];
rep(i, m) q.push(make_pair(b[i], i));
rep(i, n) {
while (!q.empty() && q.top().first >= a[i]) {
ans[q.top().second] = i + 1;
q.pop();
}
}
rep(i,m) cout<<ans[i]<<endl;
}
D - Keep Distance (abc382 D)
题目大意
给定N和M,按字典序输出所有满足以下条件的数组:
- $1 \le A_i$
- 对于i大于等于2,$A_{i-1}+10 \le A_i$
- $A_N \le M$
解题思路
这题关键点在于$10N-9 \le M \le 10N$,那么说明中间的差其实不会超过20,否则最后一个数一定会超过M。
然后暴力即可。
代码
vector<vector<int> > ans;
int n, m;
vector<int> tmp;
void dfs(int x) {
if (x == n) {
ans.pb(tmp);
return;
}
if (tmp[x - 1] + (n - x) * 10 > m) return;
for (int i = 10;i <= 20;i++) {
tmp[x] = tmp[x - 1] + i;
if (tmp[x] > m) return;
dfs(x + 1);
}
}
void solve()
{
cin >> n >> m;
tmp.resize(n);
for (int i = 1;i <= 10;i++) {
tmp[0] = i;
dfs(1);
}
cout << ans.size() << endl;
//以下为auto输出ans
for(auto v, ans) {
for(auto i, v) cout << i << " ";
cout << endl;
}
}
E - Expansion Packs (abc382 E)
题目大意
一个卡牌包里有n张卡牌,第i张卡牌是稀有牌的概率是pi。
现在将一包一包的开牌,直到开出X张稀有牌为止,问开的卡牌包数的期望是多少
解题思路
看通过人数可以发现期望放在E题不是很合适。
首先求出dp[i][j]
为一包中拆前i
张牌,有j
张是稀有牌的概率:
第i张不是稀有牌,转移:dp[i][j] = dp[i - 1][j] * (1 - p[i])
第i张是稀有牌,转移: dp[i][j] += dp[i - 1][j - 1] * p[i]
然后这个数组我们其实只用得到dp[n][i]
,其实也就是一整包中开出i
张稀有牌的概率,所以dp
其实可以滚动数组,但是这题n^2是可以存的下的。
然后设e[i]
为开出i张稀有牌的期望包数(即答案)。
那么可以考虑新开出的”一包“中有几张稀有牌,我们先假设这一包不可能没有稀有牌,那么可以很简单的得到转移:e[i]=sigma(e[i-j]*dp[n][j])+1
,就是开出i-j张稀有牌的期望*这一包开出j张稀有牌的概率,最后加上1表示我们新开了一包。
但是其实会开不出稀有牌,那么我们要先计算一下期望多少包一定开出稀有牌,是个简单的0-1概型:1/(1-dp[n][0])
,所以式子调整成e[i]=sigma(e[i-j]*dp[n][j])+1/(1-dp[n][0])
,但是此时还不对,因为内部的dp[n][j]
是包含了开不出稀有牌的概率,但我们已经将开不出稀有牌的期望放在外面计算了:
所以最后的式子应该是e[i]=sigma(e[i-j]*(dp[n][j]/(1-dp[n][0])))+1/(1-dp[n][0])
。
好在给的样例还是很有代表性的。
代码
double dp[5005][5005];
double e[5005];
void solve() {
int n, x;
cin >> n >> x;
vector<double> p(n);
for(int i=0;i<n;i++)
cin >> p[i];
p[i] /= 100.0;
}
dp[0][0] = 1.0;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= n; ++j) {
dp[i][j] = dp[i - 1][j] * (1 - p[i - 1]);
if (j > 0) {
dp[i][j] += dp[i - 1][j - 1] * p[i - 1];
}
}
}
for (int i = 1;i <= x;i++) {
for (int j = 1;j <= i;j++) {
e[i] += (e[i - j]) * (dp[n][j] / (1.0 - dp[n][0]));
}
e[i] += (1.0 / (1.0 - dp[n][0]));
}
cout << fixed << setprecision(10) << e[x];
}
标签:AtCoder,int,void,稀有,Solution,cin,382,rep,dp
From: https://www.cnblogs.com/NightRaven/p/18579176