题意:有两种温度的水,一种是热水h度的,一种是c度的冷水,倒水的顺序是这样的,热,冷,热,冷,热,冷,最后的水温是所有杯水加起来的平均值,比如倒了7杯热的,6杯凉的。$t=(7 * h+6 * c)/(6+7)$,问倒水最少多少次,可以让温度最接近H度
思路:如果倒水次数为偶数,那么温度就是(h+c)/2,如果这个温度是大于T的,那么就倒两次即可,因为如果是奇数次倒水,次数越多,温度越高的,就会逐步远离T,反之,我们知道,水温增加到一定程度,我们冷水倒x次时,会比冷水倒x+1次更接近H,那么我们可以二分答案,二分倒冷水的次数即可
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
#define double long double
#define ld long double
int a[105][105];
void solve() {
int c,h,t;
cin>>h>>c>>t;
int ans=0;
// if(h==t){
// cout<<"1\n";
// return;
// }
if(c+h>=2*t){
cout<<2<<endl;
return;
}
auto check=[&](int x){
double ans=(double)((x+1)*h+x*c)/(double)(2*x+1);
return fabs(ans-(double)t);
};
int x=(t-h)/(h+c-2*t);
int l=0,r=1e9;
while(l<=r){
int mid=l+r>>1;
if(check(mid)<=check(mid+1)){
ans=mid;
r=mid-1;
}
else{
l=mid+1;
}
}
cout<<ans*2+1<<endl;
//
// ld v=(ld)1e9;
// for (int i = max((int )0,x-1); i <=x+1 ; ++i) {
// ld res=abs((ld)((i+1)*h+i*c)/(ld)(2*i+1)-(ld)(t));
//// ld vi = abs( (ld) ((i + 1) * h + i * c) / (ld)(2 * i + 1) - (ld)(T));
// if(res<v){
// v=res;
// ans=2*i+1;
// }
// }
// cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t=1;
cin>>t;
while (t--){
solve();
}
}
题意: 给定一个数组,但不是求最大的字串和,而是求去掉某个区间的最大值,能够获得的最大的字串和为多少
思路:最大字串和可以On的求出来,那么去掉最大值其实就是假设当前的最大值是K,那么大于K的都设为区间的断点,然后我们枚举K,求加上断点之后的最大字串和,减去K,即是我们的答案
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
int a[105][105];
void solve() {
int ans=0;
int n;
cin>>n;
vector<int>a(n);
for (int i = 0; i <n ; ++i) {
cin>>a[i];
}
for (int k = 0; k <=30 ; ++k) {
auto b=a;
for (auto &i:b) {
if(i>k)i=INT_MIN;
}
int res=0,cnt=0;
for (auto i :b) {
cnt+=i;
if(cnt<0)cnt=0;
res=max(res,cnt);
}
ans=max(res-k,ans);
}
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t=1;
// cin>>t;
while (t--){
solve();
}
}
题意:有四种类型的菜,每种类型的菜有ni道菜可以选择,每道菜的价格是aj,有些菜肴不能搭配,一二种菜有m1对菜不能搭配,索引值为x,y。二三种菜有m2对菜不能搭配,三四种菜有m3种不能搭配,每一种菜都要选择一种,问如何才能最小化花费,如果不能搭配,则输出-1
思路:我们开一个multiset,枚举每一个m,然后枚举每一个右边的值,然后枚举他的边,我们从set里面删除所有的,最后求最大,删完了,说明这个位置就是无穷大
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int INF=1e15;
const int maxn=150050;
void solve() {
int n1,n2,n3,n4;
cin>>n1>>n2>>n3>>n4;
vector<int>a(n1),b(n2),c(n3),d(n4);
for (int i = 0; i <n1 ; ++i) {
cin>>a[i];
}
for (int i = 0; i <n2 ; ++i) {
cin>>b[i];
}
for (int i = 0; i <n3 ; ++i) {
cin>>c[i];
}
for (int i = 0; i <n4 ; ++i) {
cin>>d[i];
}
int m1,m2,m3;
vector<int>g1[n2];
vector<int >g2[n3];
vector<int>g3[n4];
cin>>m1;
for (int i = 0; i <m1 ; ++i) {
int x,y;
cin>>x>>y;
x--,y--;
g1[y].push_back(x);
}
cin>>m2;
for (int i = 0; i <m2 ; ++i) {
int x,y;
cin>>x>>y;
x--,y--;
g2[y].push_back(x);
}
cin>>m3;
for (int i = 0; i <m3 ; ++i) {
int x,y;
cin>>x>>y;
x--,y--;
g3[y].push_back(x);
}
multiset<int>st;
for (auto i:a) {
st.insert(i);
}
for (int i = 0; i <n2 ; ++i) {
vector<int>p;
for (auto k:g1[i]) {
st.erase(st.lower_bound(a[k]));
p.push_back(a[k]);
}
if(st.empty()){
b[i]=INF;
}
else{
b[i]+=*st.begin();
}
for (auto j:g1[i]) {
st.insert(a[j]);
}
}
st.clear();
for (auto i:b) {
st.insert(i);
}
for (int i = 0; i <n3 ; ++i) {
vector<int>p;
for (auto k:g2[i]) {
st.erase(st.lower_bound(b[k]));
p.push_back(a[k]);
}
if(st.empty()){
c[i]=INF;
}
else{
c[i]+=*st.begin();
}
for (auto j:g2[i]) {
st.insert(b[j]);
}
}
st.clear();
for (auto i:c) {
st.insert(i);
}
for (int i = 0; i <n4 ; ++i) {
vector<int>p;
for (auto k:g3[i]) {
st.erase(st.lower_bound(c[k]));
p.push_back(c[k]);
}
if(st.empty()){
d[i]=INF;
}
else{
d[i]+=*st.begin();
}
for (auto j:g3[i]) {
st.insert(c[j]);
}
}
int ans= *min_element(d.begin(),d.end());
if(ans>=INF)ans=-1;
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
//cin>>t;
while (t--){
solve();
}
}
简洁版大神diamond:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 1e18;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
vector<int> n(4);
for (auto &i: n) cin >> i;
vector<vector<int>> a(4);
for (int i = 0; i < 4; i++) {
a[i] = vector<int>(n[i]);
for (auto &j: a[i]) cin >> j;
}
for (int i = 1, m; i < 4; i++) {
cin >> m;
vector<vector<int>> e(n[i] + 1);
for (int x, y; m; m--)
cin >> x >> y, x--, y--, e[y].push_back(x);
multiset<int> cnt;
for (auto j: a[i - 1])
cnt.insert(j);
for (int j = 0; j < n[i]; j++) {
for (auto k: e[j])
cnt.erase(cnt.lower_bound(a[i - 1][k]));
if (cnt.empty()) a[i][j] = inf;
else a[i][j] += *cnt.begin();
for (auto k: e[j])
cnt.insert(a[i - 1][k]);
}
}
int res = *min_element(a[3].begin(), a[3].end());
if( res >= inf ) res = -1;
cout << res;
return 0;
}
题意:求有多少个长度为k的序列a,满足以下条件,对于所有的 $ai$,$ai<ai+1$,$1<=ai<=n$,对于任意值x,对所选序列的全排列任意顺序,取模之后,答案相同
思路:
$x%a%b=x%b%a$,又因为b>a,所以左边=$x%a$,所以$x≡x%b(mod a)$,那么设$x=tb+y$,右边$(tb+y)%b=y$,得到$tb+y≡y(mod a)$,由于t是任意的,那么只有a能够整除b时,等式才能恒成立,那么我们推广到整个数列,得出结论,序列中的每一个数都是最小数的倍数
那么我们就可以枚举第一位数字,然后组合数选出k-1个倍数即可。
diamond:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>PII;
const int N=1e5+5,M=1e5+5,INF=0x3f3f3f3f,Mod=998244353;
#define mod Mod
const double eps=1e-8;
typedef long long ll;
#define int long long
//ll a,b;
//int n,p;
int n;
int ksm(int x,int y,int p){
int res=1;
while(y){
if(y&1)res=(ll)res*x%p;
x=(ll)x*x%p;
y>>=1;
}
return res;
}
int c(int a,int b,int p){
if(b>a)return 0;
int res=1;
for(int i=1,j=a;i<=b;++i,--j){
res=(ll)res*j%p;
res=(ll)res*ksm(i,p-2,p)%p;
}
return res;
}
int Lucas(ll a,ll b,int p){
if(a<p&&b<p)return c(a,b,p);
return (ll)c(a%p,b%p,p)*Lucas(a/p,b/p,p)%p;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int k;
cin>>n>>k;
int ans=0;
for (int i = 1; i <=n ; ++i) {
ans=(ans+ Lucas(n/i-1,k-1,mod))%mod;
}
cout<<ans<<'\n';
return 0;
}