做题小结
好像身不由己 不能自己很失败
细细品味这一首歌 又记起来了hjk。
https://www.luogu.com.cn/problem/CF2024B

这个题也是逆天了 总结 我没做出来
然后我讲下我补题的思路吧 不知道和正解一样不一样
首先最基本的思路 就是我们先对所有的取一个min 这个就是一开始要拿的
再剔除最小值 然后一直重复这个操作 知道拿到k个为止
不过写起来我应该是写头晕了 昏招频出
#include<bits/stdc++.h>
#define int long long
#define debug cout<<endl<<"----------"<<endl;
const int range = 2e5+10;
using namespace std;
int n, k;
int a[range];
int s[range];
int lowbit(int x) {
return x & -x;
}
void change(int x, int k) {
while (x <= n)s[x] += k, x = x + lowbit(x);
}
int query(int x) {
int t = 0;
while (x)t += s[x], x = x - lowbit(x);
return t;
}
int pre[range];
void solve(int t ) { //多测
cin >> n >> k;
map<int,int>ma;
/*
2 +4+2
*/
priority_queue<int, vector<int>, greater<int >> q;
for(int i = 1; i <= n; i++) {
cin >> a[i];
ma[a[i]]++;
}
sort(a+1,a+1+n);
int mini=a[1];
if(n*mini>=k){
cout<<k<<endl;return ;
}
int ans=0;
int cy=mini;
k-=n*cy;
ans=cy*n+1;
for(int i=2;i<=n;i++)
{
int temp=a[i];
a[i]-=cy;
if(a[i]==0)ans++;
else {
if((n-i+1)*a[i]>=k){
ans+=k;
cout<<ans<<endl;return ;
}
ans+=(n-i+1)*a[i]+1;
cy=temp;
k-=a[i]*(n-i+1);
// cout<<cy<<" "<<i<<endl;
}
}
cout<<ans<<endl;
// int sum = 0;
// int ans = 0;
// while (sum < k) {
// int w = min(q.top(), k - sum);
// int u = q.top();
// q.pop();
// u -= w;
// sum+=w;
// ans += w;
// if(sum>=k)break;
// if (u == 0) {
// ans++;
// }
// }
// cout<<ans<<endl;
//
for(int i=2;i<=n;i++)
{
int temp=a[i];
a[i]-=cy;
if(a[i]==0)ans++;
else {
if((n-i+1)*a[i]>=k){
ans+=k;
cout<<ans<<endl;return ;
}
ans+=(n-i+1)*a[i]+1;
cy=temp;
k-=a[i]*(n-i+1);
// cout<<cy<<" "<<i<<endl;
}
}
如果ai取完一边不行 那么就继续 这没话说
如果可以的话 这边我真的很傻逼 比如5 5 5 8 9 我们要取5 一遍
我以为要+额外的5的数量-1 算作犯错机会 其实想多了 我们是很聪明的 手里记着多少呢
每个取5个就行 不用额外犯错
https://www.luogu.com.cn/problem/CF2027C

草 实在没想到 自己现在菜的离谱了 黄题都切不出来 以前切绿就跟切菜一样。。
退役老年选手 太卑微
当时思考到了做法这些 奈何思维退化 码力变弱
第一个做法 其实就是记忆化搜索 其实改改就是一个dfs图
这个挺好的一个思路
map<int, vector<int >> ma;
map<int, int>dp;
int dfs(int x)
{
if(dp[x])return dp[x];
int ans=x;
dp[x]=ans;
for(auto i:ma[x]){
ans=max(ans,dfs(i+x));
}
dp[x]=ans;
return dp[x];
}
void solve(int t ) { //多测
cin >> n ;
dp.clear();
ma.clear();
for (int i = 1; i <= n; i++) {
cin >> a[i];
if(i==1)continue;//防止死循环
if(a[i]+i-1-n>=0)
ma[a[i] + i - 1 - n].push_back(i - 1);
}
cout<<dfs(0)+n<<endl;
第二个是 朴素写法
用set记录重复出现的 如果出现了 就把贡献加上去
(我认为的朴素写法)
set<int>s;
pair<int, int>p[range];
bool cmp(pair<int, int>x, pair<int, int>y) {
if (x.first == y.first)return x.second < y.second;
return x.first < y.first;
}
void solve(int t ) { //多测
cin >> n ;
s.clear();
for (int i = 1; i <= n; i++) {
cin >> a[i];
p[i].first = a[i] + i - 1;
p[i].second = i - 1;
}
s.insert(n);
sort(p + 1, p + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
if (s.count(p[i].first)) {
s.insert(p[i].first + p[i].second);
}
}
cout << *s.rbegin() << endl;
通过这道题 也学到了东西
https://www.luogu.com.cn/problem/CF2032C

三角形 就是第二条边大于第三边 这道题一个二分 一个双指针写法
我投降 我没写出来 现在就是思路能想一些出来 慢慢的就会做出来了 还在恢复
第一个就是双指针了 无论怎么改变 数组中的值还是那几个 又不能凭空变出来
先sort排序
所以 我们可以想到一个On的写法 用for循环卡住某个i 表示什么呢
如果此时l与l+1是比你大的 意味着 选你做老大就好了 那么我们只需要改变
l之前的与你之后的 然后比较下答案就行
for(int r=2;r<=n;r++)
{
while(a[l]+a[l+1]<=a[r])l++;
ans=min(ans,l-1+n-r);
}
二分写法 经典Onlogn 用for循环卡住i
我当时就在想 一个最大值 一个最小值 我咋卡两个东西
人到无语是会笑的 太久没写题就是这样的 我以前做烂的模型。。
就是一个for循环卡住就行了 枚举最大值就行
二分一个mid表示最小 其实和双指针没什么区别
int ans = 1e9;
for (int i = n; i >= 2; i--) {
int l = 1;
int r = i - 1;
//二分最小值
int w = 0;
while (l <= r) {
int mid = l + r >> 1;
if (a[mid] + a[mid + 1] > a[i]) {
w = mid;
r = mid - 1;
} else l = mid + 1;
}
// cout<<i<<" "<<w<<endl;
ans = min(ans, w - 1 + n - i);
}
cout<<ans<<endl;
https://www.luogu.com.cn/problem/CF2028B

这题大部分代码都想到了 就是一个 //我默认n=n-1的
然后我在判断 x=0时 错了 我认为都可以的 。。。
错在这里了 其实不是
if(x==0)
{
bool flag=0;
if(y<=n)flag=1;
cout<<n+1-flag<<endl;
return ;
}
仔细 写写就能发现了 如果你给n=8 n-1=7 给的y时6那我可以办到 如果n=9要8我就不行了
也是 没注意样例细节 想当然了
所以答案就出来了
if(y+1>=n){
/*
6 7
*/
if(y<=n)flag=1;
cout<<n+1-flag<<endl;
return ;
}
https://www.luogu.com.cn/problem/CF2028C

这题我做错了 我思考少了 我知道是双指针
这题先打住 需要回头补下二分写法 1.17
1.22补
这题其实题解双指针麻烦了 我们其实只要意识到一个点也是贪心思维 就是他是碰到可以切就切的 所以能切几份是固定的
for (int i = 1; i <= n; i++) {
now += a[i];
if (now >= v) {
pre[i] = pre[i - 1] + 1;
now = 0;
} else pre[i] = pre[i - 1];
}
now = 0;
for (int i = n; i >= 1; i--) {
now += a[i];
if (now >= v) {
suf[i] = suf[i + 1] + 1;
now = 0;
} else suf[i] = suf[i + 1];
}
只要求一个前后缀就行
只有统计答案才会纠结取不取
然后后续统计答案 我们只要枚举一个l r 即可
用双指针枚举l r会很方便 很基础的的写法
for(int l=1;l<=n;l++)
{
while(r<n&&pre[l-1]+suf[r+2]>=m)r++;
ans=max(ans,sum[r]-sum[l-1]);
}
用二分就有一点的难写 不过也是基本模型 卡一边
for (int i = 1; i <= n; i++) {
int r = n;
int l = i;
// debug
// cout << i << endl;
while (l <= r) {
int mid = l + r >> 1;
// cout << mid << endl;
if (check(i, mid)) {
// cout<<l<<" "<<mid<<endl;
ans = max(sum[mid] - sum[i - 1], ans);
l = mid + 1;
// break;
} else r = mid - 1;
}
}
原题链接 方便看我的rz提交记录
https://codeforces.com/contest/2031/problem/B
https://www.luogu.com.cn/problem/CF2031B

逆天题目 wa了半天还是没做出来 看了题解 感觉自己是弱智
很明显的 对于一个数 如果他不在i+1 i i-1三个位置 永远变不回去 这是肯定的
然后就没了 果然人类精华
https://codeforces.com/contest/2031/problem/C

热知识 0和1都是完全平方数
这题考了1是完全平方数 明早写吧 刚补没多久
这题有点逆天 n是偶数 直接两个两个输出
n是奇数 就有点麻烦了 如果按照n是偶数的方法去写 一定会有一个多出来 那怎么解决呢 我是没想到的
不过这一个和勾股定理有关
n是奇数 -1 就是偶数
如果可以解决3的话 就可以解决奇数了 但是3是放不了的 5也是 一直到27才可以 我是看测试点才知道的
为什么呢 因为32+42=5^2这是一组最小的勾股定理
所以我们可以这样思考 一个放1 一个放10 一个放 26 刚好可以
于是就可以愉快的写了
不过还要注意一个就是由于10写了1那么 后续继续两个两个补就因为26又给隔开了
1 2 2 3 3 4 4 5 5 1 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 1 13
13和13 就隔开了 就不行 解决办法是第11个位置和27刚好是16所以可以单独搞下
这题个人认为是个绿 不好想的

浙公网安备 33010602011771号