鴿了好多場的題解,這場不鴿了.
關鍵這場我也沒打呀
Cue一下隊友鏈接:
核心選手:https://me.csdn.net/qq_43559193
核心選手:https://me.csdn.net/weixin_43916298
比賽鏈接:https://codeforces.com/contest/1359
目錄
比賽鏈接:https://codeforces.com/contest/1359
D. Yet Another Yet Another Task
A. Berland Poker
題目大意:
具體沒怎麼讀,看了看樣例和解釋,大概理解了個意思,瞎寫。
題目大體意思應該是 求一個每人手中小丑牌的最大值 - 其他人中最小值 (大概是這樣,我也沒讀題)
題目思路:
然後就很水了呀:
如果小丑牌小於等於每個人應得的手牌,那麼肯定是小丑牌數量。
否則一個人全拿,剩下的平分(上取整),然後求一下答案
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-7;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);read(m);read(p);
ll temp = n/p;
if(temp>=m) printf("%lld\n",m);
else{
ll diff = m - temp;
printf("%lld\n",temp - ((diff+p-2)/(p-1)));
}
}
return 0;
}
/**
* 10 *
0000 1111
**/
B. New Theatre Square
題目大意:
輸入n,m,x,y 代表有n*m的矩陣,塗1*1的格子需要x,塗1*2的格子需要y,問最少花費多少使得圖中所有的'.'均被染色
題目思路:
首先可以得出 如果2*x <= y ,ans = ‘.’的個數 * x
否則,全塗1 * 2 剩下的塗1,然後可以發現 1*2只可以橫着塗,那麼就遍歷一下就行了
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-7;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
char str[1005][1005];
vector<char>v;
int main(){
int T;scanf("%d",&T);
while(T--){
ll x,y;read(n);read(m);
read(x);read(y);
for(int i=1;i<=n;i++) scanf("%s",str[i]+1);
int cot = 0;
for(int i=1;i<=n;i++){
for(int k=1;k<=m;k++){
if(str[i][k]=='.') cot ++;
}
}
if(2*x <= y) printf("%lld\n",1ll*cot*x);
else{
ll ans = 0;
for(int i=1;i<=n;i++){
int cnt = 1;
for(int k=2;k<=m;k++){
if(str[i][k]!=str[i][k-1]){
int res = cnt%2;
if(str[i][k]=='*')
ans+=(cnt/2)*y+res*x;
cnt = 1;
}
else cnt++;
}
int res = cnt%2;
if(str[i][m]=='.')
ans+=(cnt/2)*y+res*x;
}
printf("%lld\n",ans);
}
}
return 0;
}
/**
* 10 *
0000 1111
**/
C. Mixing Water
題目大意:
輸入a,b,t,a代表一杯熱水的溫度,b代表一杯冷水的溫度,每次可以倒一杯熱水後,再倒一杯冷水,然後..依次類推,最終的溫度是這些的平均值,問最少倒幾次使得其可以最接近溫度t
題目思路:
首先兩種情況:
假設熱水到了x次
1.假設倒的次數爲偶數,那麼此時,所以次數爲偶數時不需要考慮,只需要記錄2的答案就可以
2.假設倒的次數爲奇數,那麼此時,所以此時無需多言,盲猜具有單調性,直接二分寫,發現確實具有單調性...,剩下的就是二分怎麼寫了。
這題正解應該是解方程吧..二分直接卡死精度了,精度到1e-15才過
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
double cal(ll x){
double tempx = x/2+1,tempy = x/2;
return (tempx*n+tempy*m)/(x*1.0);
}
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);read(m);read(p);
if(2*p == n+m) printf("2\n");
else if(n==p) printf("1\n");
else{
int ans = 2;
double diff = abs((double)(n+m)*0.5-(double)p);
ll l = 1, r = 1e9+7;
double ans_left = -1,ans_right = -1;
while(l<=r){
ll mid = (l+r)/2;
double res = cal(2*mid-1);
if(res-p>eps){
ans_right = 2*mid-1;
l = mid+1;
}
else{
ans_left = 2*mid-1;
r = mid-1;
}
}
if(ans_left!=-1)
if(abs(cal(ans_left)-p)-diff<eps) ans = ans_left,diff = abs(cal(ans_left)-p);
if(ans_right!=-1)
if(abs(cal(ans_right)-p)-diff<eps) ans = ans_right,diff = abs(cal(ans_right)-p);
printf("%d\n",ans);
}
}
return 0;
}
/**
* 10 *
0000 1111
**/
D. Yet Another Yet Another Task
題目大意:
抽象一下:選擇一個區間,讓這個區間減去當前區間最大值,求這種答案的最大值
題目思路:
經典套路了,直接秒掉就可以了
枚舉一下最大值的位置,單調棧維護最大值可控區間,查一下前綴和的最大值最小值,計算答案就可以了。
本着優化算法的初衷,直接把區間查詢換成O1查詢的st表,124ms跑到起飛。
這題正解的話應該是枚舉30個值作爲最大值 複雜度30*n 不過st表預處理也就lgn的複雜度 ,複雜度20*n
所以,哪個好寫寫哪個咯
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-7;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m;
int st[maxn];
int pre[maxn],cur[maxn];//表示前方可以控制到多少,後方可以控制到多少。
ll num[maxn];
ll st_max[maxn][20],st_min[maxn][20];
ll lg[maxn];
ll f[maxn];
void work()
{
ll cnt=0;
for(int i=1;i<=n;i++)
lg[i]=lg[i/2]+1;
for(int i=0;i<=n;i++)
st_max[i][0]=st_min[i][0]=f[i];
for(int j=1;j<=25;j++)
for(int i=0;i+(1<<j)-1<=n;i++){
st_max[i][j]=max(st_max[i][j-1],st_max[i+(1<<(j-1))][j-1]);
st_min[i][j]=min(st_min[i][j-1],st_min[i+(1<<(j-1))][j-1]);
}
}
ll query_max(ll x,ll y)
{
ll len=lg[y-x+1]-1;
return max(st_max[x][len],st_max[y-(1<<len)+1][len]);//爲啥+1
}
ll query_min(ll x,ll y)
{
ll len=lg[y-x+1]-1;
return min(st_min[x][len],st_min[y-(1<<len)+1][len]);//爲啥+1
}
void get_min(){
int bg=0;
st[0]=0;
for(int i=1;i<=n;i++){
while(bg!=0&&num[i]>=num[st[bg]])
bg--;
pre[i]=st[bg];
st[++bg]=i;
}
bg=0;
st[0]=n+1;
for(int i=n;i>=1;i--){
while(bg!=0&&num[i]>=num[st[bg]])
bg--;
cur[i]=st[bg];
st[++bg]=i;
}
for(int i=1;i<=n;i++) pre[i]++,cur[i]--;
}
int main(){
read(n);
for(int i=1;i<=n;i++){
read(num[i]);
f[i] = f[i-1] + num[i];
}
work();
get_min();
ll maxl = 0;
for(int i=1;i<=n;i++){
ll temp = query_max(i,cur[i]) - query_min(pre[i]-1,i-1);
maxl = max(maxl,temp-num[i]);
}
printf("%lld\n",maxl);
return 0;
}
/**
* 10 *
0000 1111
**/
下面看一下E題,哦數論或者組合數學呀,打擾了,爭取不鴿你。