#include
#include
using namespace std;
long long N;
//计算组合数
long long C(int a, int b)
{
long long sum = 1;
for (int i = a, j = 1; j <= b; i--, j++)
{
sum = sum*i / j;
if (sum>N)
{
return sum;
}
}
return sum;
}
bool check(int k)
{
long long rRow = 2 * k;//斜着看的那一行 以第k行为基准 右斜上有 2k个行
long long lRow = max(rRow, N);//斜着看的那一行 左斜下是找N和rightRow 最大值
while (rRow<lRow)
{
int mid = rRow + lRow >> 1;
if (C(mid, k) >= N)
{
lRow = mid;
}
else
{
rRow = mid + 1;
}
}
if (C(lRow, k) !=N )return false;
else
{
cout << (long long)((1 + lRow)*lRow / 2 + (k + 1));
return true;
}
}
int main() {
cin >> N;
for (int i = 16; ;i--)
{
if (check(i))break;
}
return 0;
}
#include
#include
using namespace std;
const int N = 100010;
struct Node{
int t, d;
bool operator<(const struct Node & n) const{
return t * n.d < n.t * d;
}
}node[N];
int n;
int main()
{
cin >> n;
for(int i = 0; i < n; i++){
int a,b;
scanf("%d%d",&a,&b);
node[i].t = a;
node[i].d = b;
}
std::sort(node,node + n);
long long time = 0;
long long res = 0;
for(int i = 0; i <= n; i++)
{
res += time * node[i].d;
time += node[i].t;
}
cout<< res << endl;
}
#include
#include
#include
using namespace std;
struct iceInfo {
long long Ti;
long long Di;
iceInfo(int t, int d) :Ti(t), Di(d) {}
bool operator< (const iceInfo &cei) const {
//以融化体积为基准来进行排序,搬运当前冰块 不会产生损耗
return this->Ti * cei.Di < this->Di * cei.Ti; //这个意思是先搬运this 后 cei的损耗 和 先搬运cei后this 的损耗 进行比较。
}
};
int main() {
long long N;
long long sum = 0;//搬完后冰块融化总量
long long time = 0;//搬运时间
int T, D;
set<iceInfo> sIce;
cin >> N;
for (int i = 0; i < N; i++) {
cin >> T >> D;
iceInfo ice(T, D);
sIce.insert(ice);
}
for (set<iceInfo> ::iterator it = sIce.begin(); it != sIce.end(); it++) {
sum += time * it->Di;
time += it->Ti;
}
cout << sum << endl;
return 0;
}
二分法、check函数的逻辑代码理解
参考:打包.
#include
using namespace std;
bool check(int weg[], int mid, int N, int M) {
int curWeight = 0;
int curM_Num = 1;
for (int i = 0; i < N; i++) {
if ( weg[i] > mid) {//如果超过目标包裹总数 礼物无法以最大包裹容量打包成对应包裹数目。
return false;
}
curWeight += weg[i];
if (curWeight > mid) {//如果大于当前包裹容量 再打一个新包
curWeight = weg[i];
curM_Num++;
}
}
return curM_Num <= M;
}
int main() {
long long N;
long long M;
cin >> N >> M;
int gifWeg[100010];
long long right = 0;
long long left = 0;
long long mid = 0;
for (int i = 0; i < N; i++) {
cin >> gifWeg[i];
right += gifWeg[i];
}
//二分法
while (left < right) {
mid = (left + right) / 2;
if (check(gifWeg, mid, N, M)) {
right = mid;
}
else {
left = mid + 1;
}
}
cout << left;
return 0;
}
思路:先对vec进行左边界排序(小到大),然后考虑三种情况并依次判断
res
容器弹出尾部元素,插入新元素的情况res
容器的尾部元素左边界 相等那就取右边界最大的那个res
容器元素个数大于2的情况下, 即将插入尾部的v[i]的左边界 小于 res
容器中倒数第二个元素的右边界res
容器中尾部元素的右边界。#include
#include
#include
using namespace std;
struct Node {
long long x;
long long y;
};
vector<Node> vec;
vector<Node> res;
bool mycmp(Node &a,Node &b) {
return a.x < b.x;
}
long long coLine(vector<Node>&v, vector<Node>&r,long n) {
r.push_back(v[0]);
for (int i = 1; i < v.size(); i++) {
if ( (( (r[r.size() - 1].x == v[i].x ||(r.size() >= 2 && r[r.size() - 2].y >= v[i].x)) && r[r.size() - 1].y < v[i].y)) ) {
r.pop_back();
r.push_back(v[i]);
}
else if (r[r.size() - 1].y >= v[i].x && r[r.size() - 1].y < v[i].y) {
r.push_back(v[i]);
}
}
if (r[r.size() - 1].y < n) return -1;
else return r.size();
}
int main() {
long long n, m;
cin >> n >> m;
Node mynode;
for (long long i = 0; i < m; i++) {
cin >> mynode.x >> mynode.y;
vec.push_back(mynode);
}
sort(vec.begin(), vec.end(), mycmp);
cout << coLine(vec, res, n);
}
这题没做出来,留给大家想想,提一点 跟和谐宿舍2有点区别,是求最大木板面积的最小值。。
主要是dp数组定义吧、或者用贪心思想 。
#include
#include
using namespace std;
int dp[101][101];//用i块木板遮住前j幅画的面积最小值
int mj[101][101];//保存i~j幅画最大的高度值
int h[101];//保存每幅画的高度
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>h[i];
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
mj[i][j]=max(mj[i][j-1],h[j]);//找出i~j幅画的最大高度
for(int i=1;i<=n;i++)
dp[1][i]=mj[1][i]*i;//赋值边界1块板时
for(int i=2;i<=m;i++)
for(int j=1;j<=n;j++)
if(j<=i)//板数大于画数,每个画用一个板子面积最小
for(int m=1;m<=j;m++)
dp[i][j]+=h[m];
else
for(int k=1;j-k>=i-1;k++)//因为不知道前面几个画的分组情况和后几个画为一组面积最小所以需要循环判断
if(k==1)
dp[i][j]=dp[i-1][j-k]+mj[j-k+1][j]*k;//第一次赋值,否则直接比较全为0
else
dp[i][j]=min((dp[i-1][j-k]+mj[j-k+1][j]*k),dp[i][j]);
cout<<dp[m][n];
return 0;
}
#include
#include
#include
#include
using namespace std;
struct Node {
long long x;
long long y;
};
vector<Node> vecL;
bool mycmp(Node &a,Node &b) {
return a.x < b.x;
}
int main() {
int n ;
cin >> n;
Node node;
//vector res;
stack<int> stN;
for (int i = 0; i < n; i++) {
cin >> node.x >> node.y;
vecL.push_back(node);
}
sort(vecL.begin(), vecL.end(), mycmp);//按左边界排序
//res.push_back(vecL[0]);
stN.push(0);
long long left = vecL[0].x;
long long right = vecL[0].y;
long long sum = 0;
for (int i = 1; i < vecL.size(); i++) {
if (vecL[stN.top()].y >= vecL[i].x &&vecL[stN.top()].y <= vecL[i].y) {//遇到该情况更新右边界
stN.push(i);
right = vecL[i].y;
}
else if(vecL[stN.top()].y < vecL[i].x){//遇到该情况开始计算覆盖区间,并更新left 和 right
sum += right - left;
stN.push(i);
left = vecL[i].x;
right = vecL[i].y;
}
if (i == vecL.size() - 1) {//防止vecL无断层的情况下,没有计算覆盖区间
sum += right - left;
}
}
cout << sum;
return 0;
}
#include
using namespace std;
bool mycmp(int a,int b) {
return a > b;
}
int main() {
int n,m,typeN,dIndex;
cin>>n>>m;
vector<int> vec;
for(int i = 1;i <= n;i++) {
vec.push_back(i);
}
// for(vector::iterator it = vec.begin();it!=vec.end();it++) {
// cout<< *it;
// }
for(int i = 0;i<m;i++) {
cin>>typeN>>dIndex;
if(typeN == 0) {
sort(vec.begin(),vec.begin()+dIndex,mycmp);
} else {
sort(vec.begin()+dIndex-1,vec.end());
}
// for(vector::iterator it = vec.begin();it!=vec.end();it++) {
// cout<< *it;
// }
// cout<
}
for(vector<int>::iterator it = vec.begin();it!=vec.end();it++) {
cout<< *it<<" ";
}
return 0;
}
题解链接.
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=5003,mod=1e9+7;
int n;
char s[N];
long long f[N][N];//f[i][j]表示前i个序列中左括号比右括号多j个的合法方案数
long long cal()//计算插入括号合法方案数
{
memset(f,0,sizeof f);
f[0][0]=1;//初始化
for(int i=1;i<=n;i++)
{
if(s[i]=='(')
{
for(int j=1;j<=n;j++)
f[i][j]=f[i-1][j-1];
}
else
{
f[i][0]=(f[i-1][0]+f[i-1][1])%mod;//注意0的时候需要特殊处理一下,因为j-1=-1,所以我们不能用化简后的递推式去计算,只能用化简前的递推式去计算
for(int j=1;j<=n;j++)
f[i][j]=(f[i-1][j+1]+f[i][j-1])%mod;
}
for(int i=0;i<=n;i++)//答案要求我们插入的括号数尽量小,所以要从小向大枚举,右括号的数目是不变的,当加入尽量小的左括号且有解时就返回即可
if(f[n][i]) return f[n][i];
}
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
long long ans1=cal();//记录左括号的插入方案数
reverse(s+1,s+n+1);//将原序列逆置
for(int i=1;i<=n;i++)
if(s[i]=='(') s[i]=')';
else s[i]='(';
long long ans2=cal();//记录右括号的插入方案数
printf("%lld",ans1*ans2%mod);
return 0;
}