2022.3.15
蓝书
AcWing 125. 耍杂技的牛
思路:和国王游戏很像,贪心的时候需要考虑两个属性,牛的重量和力量。以牛的重量和力量的和从小到大排序可以使得最大的风险值最小,利用啥临项微扰啥的可以证明,让序列变得有序不会让结果变坏,但有逆序对不会让结果变好。然后从小到大更一下牛的最大的风险值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=5e4+10,INF=1e8;
pll cow[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for(int i=1;i<=n;i++)
{
ll w,s;
cin >> w >> s;
cow[i]={w+s,s};
}
sort(cow+1,cow+1+n);
ll res=-1e9,sum=0;
for(int i=1;i<=n;i++)
{
res=max(res,sum-cow[i].second);
sum+=cow[i].first - cow[i].second;
}
cout << res;
return 0;
}
AcWing 126. 最大的和
二维前缀和
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100+10,INF=1e8;
int a[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
for (int i = 1; i <= n;i++)
{
for (int j = 1; j <= n;j++)
{
cin >> a[i][j];
a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
}
}
int ans = -INF;
for (int x1 = 1; x1 <= n;x1++)
for (int y1 = 1; y1 <= n;y1++)
for (int x2 = 1; x2 <= x1;x2++)
for (int y2 = 1; y2 <= y1;y2++)
{
ans = max(ans, a[x1][y1] - a[x1][y2 - 1] - a[x2 - 1][y1] + a[x2 - 1][y2 - 1]);
}
cout << ans;
return 0;
}
AcWing 127. 任务
思路:对于每个任务完成需要的时间从大到小排序,对于每个任务优先找到能够完成该任务的机器,并将它们都加入到集合里,二分找到机器完成时间最合适的那个,然后删除该机器。这样的插入和删除的操作需要用到multiset。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N=1e5+10,INF=1e8;
PII jq[N], rw[N];
int n, m;
int main()
{
while(~scanf("%d%d",&n,&m))
{
for (int i = 1; i <= n;i++)
scanf("%d%d", &jq[i].first, &jq[i].second);
for (int i = 1; i <= m;i++)
scanf("%d%d", &rw[i].first, &rw[i].second);
sort(jq + 1, jq + 1 + n);
sort(rw + 1, rw + 1 + m);
multiset<int> st;
ll ans = 0, cnt = 0;
for (int i = m, j = n; i >= 1;i--)
{
while (j >= 1 && jq[j].first >= rw[i].first)
{
st.insert(jq[j--].second);
}
auto t = st.lower_bound(rw[i].second);
if(t!=st.end())
{
ans += 500 * rw[i].first + 2 * rw[i].second;
cnt++;
st.erase(t);
}
}
printf("%lld %lld\n", cnt, ans);
}
return 0;
}
CFAB题特训赛3
B - POW
判断c是奇数还是偶数,是偶数的话直接比较绝对值,奇数的话需要绝对值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int a, b, c;
cin >> a >> b >> c;
if(c&1)
{
if(a>b)
cout << ">";
else if(a==b)
cout << "=";
else
cout << "<";
}
else
{
if(abs(a)>abs(b))
cout << ">";
else if(abs(a)==abs(b))
cout << "=";
else if(abs(a)<abs(b))
cout << "<";
}
return 0;
}
D - Fault-tolerant Network
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
ll a[N],b[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
int n;
cin>>n;
for (int i = 1; i <= n;i++)
cin >> a[i];
for (int i = 1; i <= n;i++)
cin >> b[i];
ll ans = min(abs(a[1] - b[1]) + abs(a[n] - b[n]), abs(a[1] - b[n]) + abs(a[n] - b[1]));
ll r1 = 1e9, r2 = 1e9, r3 = 1e9, r4 = 1e9;
for (int i = 1; i <= n;i++)
{
r1 = min(r1, abs(a[1] - b[i]));
r2 = min(r2, abs(a[n] - b[i]));
r3 = min(r3, abs(b[1] - a[i]));
r4 = min(r4, abs(b[n] - a[i]));
}
ans = min({ans, r1 + r2 + r3 + r4, abs(a[1] - b[1]) + r2 + r4, abs(a[1] - b[n]) + r2 + r3, abs(a[n] - b[1]) + r1 + r4, abs(a[n] - b[n]) + r1 + r3});
cout << ans << '\n';
}
return 0;
}
E - Kth Excluded
思路:对于每个被取出的数,假设a[1]=2,则说明第一个数3前面有2个数是在原序列的,a[2]=3则说明第二个数5前面有3个数在原序列,以此类推。然后我们在查询原序列的第k大的时候,如果输入的数是x只要二分找到第一个大于x的a[t],说明前面还有x个数是被单独提出来的,要找到真正的第k大还得往后挪t-1个位置,结果就是x+t-1
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
ll a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
for (int i = 1; i <= n;i++)
{
ll x;
cin >> x;
a[i] = x - i;
}
while(m--)
{
ll x;
cin >> x;
int t = lower_bound(a + 1, a + 1 + n, x) - a;
cout << t + x - 1<<'\n';
}
return 0;
}
F - Coloring a Tree
思路:观察发现每次染一个节点,它下面的子树都会被染上相同的颜色,所以我们只能从上往下涂色,当子节点和他的父亲颜色不一样的时候就需要染色了,这样遍历到最深的子节点就行。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e4+10,INF=1e8;
int c[N],h[N],cnt,vis[N],ans;
struct node
{
int ne, to;
} edge[N*2];
void add(int a,int b)
{
edge[++cnt].to = b;
edge[cnt].ne = h[a];
h[a] = cnt;
}
void dfs(int x)
{
for (int i = h[x]; i;i=edge[i].ne)
{
int j = edge[i].to;
if(c[j]!=c[x])
ans++;
//vis[j] = 1;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for (int i = 2; i <= n;i++)
{
int x;
cin >> x;
add(x, i);
//add(i, x);
}
for (int i = 1; i <= n;i++)
{
cin >> c[i];
}
for (int i = 1; i <= n;i++)
dfs(i);
cout << ans+1;
return 0;
}
G - Summer sell-off
思路:先把所有天数能卖的最小值都算出来,即min(k,l)*X。然后枚举每个天数如果翻倍的话还能多赚多少钱,此时注意需要减去没有促销时赚到的钱,这一部分不属于多赚的钱。然后把能多赚钱的天从大到小排序,选择相应次数即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int a[N],b[N],c[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
ll sum = 0;
cin >> n >> m;
for (int i = 1; i <= n;i++)
{
cin >> a[i] >> b[i];
}
int t = 0;
for (int i = 1; i <= n;i++)
{
int k = min(a[i], b[i]);
sum += k;
if(a[i]*2>=b[i])
c[++t] = b[i]-k;
else
c[++t] = a[i] * 2 - k;
}
sort(c + 1, c + 1 + t);
for (int i = t; i >= 1,m>0;i--,m--)
{
sum += c[i];
}
cout << sum;
return 0;
}
H - Leha and Function
对于F(n,k) n越大,k越小;当数组A递减,数组B递增时满足题意
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
int a[N], c[N];
pii b[N];
bool cmp(pii a, pii b) { return a.first > b.first; }
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
for (int i = 1; i <= n;i++)
{
cin >> a[i];
}
for (int i = 1; i <= n;i++)
{
cin >>b[i].first;
b[i].second = i;
}
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + n,cmp);
for (int i = 1; i <= n;i++)
{
c[b[i].second] = a[i];
}
for (int i = 1; i <= n;i++)
cout << c[i]<<' ';
return 0;
}
I - Tour
思路;遍历每个点连到的边,能到答案+1
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2000+10,INF=1e8;
int h[N],vis[N],cnt;
struct node
{
int ne, to;
}edge[N];
void add(int a,int b)
{
edge[++cnt].to = b;
edge[cnt].ne = h[a];
h[a] = cnt;
}
void dfs(int x)
{
if(vis[x])
return;
vis[x] = 1;
for (int i = h[x]; i; i = edge[i].ne)
{
if(!vis[edge[i].to])
{
dfs(edge[i].to);
vis[edge[i].to] = 1;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m,sum=0;
cin >> n >> m;
for (int i = 1; i <= m;i++)
{
int a,b;
cin >> a >> b;
add(a, b);
}
for (int i = 1; i <= n;i++)
{
dfs(i);
for (int j = 1; j <= n;j++)
if(vis[j])
sum++;
memset(vis, 0, sizeof vis);
}
cout << sum;
return 0;
}
J - Increase Subarray Sums
思路:前缀和,对于0到k,利用i和j枚举每一段的前缀和最大值,有点双指针的意思,设该段长度为i,那么答案为长度为i的前缀和加上min(i,k)*x
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=5000+10,INF=1e8;
int a[N], s[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n, x;
cin >> n >> x;
for (int i = 1; i <= n;i++)
{
cin >> a[i];
s[i] = -1e9;
}
for (int i = 1; i <= n;i++)
{
int sum = 0;
for (int j = i; j <= n;j++)
{
sum += a[j];
s[j - i + 1] = max(s[j - i + 1], sum);
}
}
for (int k = 0; k <= n;k++)
{
int ans = 0;
for (int i = 0; i <= n;i++)
{
ans = max(ans, s[i] + min(i, k) * x);
}
cout << ans << ' ';
}
cout << '\n';
cout<<s[0]<<endl;
}
return 0;
}
K - Number Game
思路:如果一开始拿到的就是1的话必输,如果拿到的是2或者是一个奇数的话必赢。因为2-1就是1,奇数除以本身也是1.对于其他情况我们需要考虑,此时的数必然是一个偶数,对于这个偶数我们需要看它是否具有奇数的因子,如果有的话我们可以除以奇数因子得到偶数给对手,此时对手只能-1,得到一个奇数,我们再让这个奇数除以自身就赢,特别注意这个除以奇数得到的偶数不能是2,不然对手直接-1就输了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
if(n==1)
cout << "FastestFinger";
else if(n==2||n&1)
cout << "Ashishgup";
else
{
int f = 0;
int x = sqrt(n);
for (int i = 2; i <=x ;i++)
{
if(n%i==0)
{
if(i&1&&(n/i)!=2)
f = 1;
if((n/i)&1&&i!=2)
f = 1;
}
if(f)
break;
}
if(f)cout<<"Ashishgup";
else
cout << "FastestFinger";
}
cout << '\n';
}
return 0;
}
L - Cooking
思路:有两个烤箱,一共n个东西要烤但烤箱每次只能烤一个东西,因此我们要求两个烤箱用的时间最好是差不多的,这样算下来时间花费是最小的。问题转化为在所有要烤的东西的时间之和李找到和不超过等于总和的一半的部分和,用总和减去这部分和就是最小花费。转化成01背包问题,一个容量为sum/2的背包能装的最大值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100+10,INF=1e8;
int dp[100010], w[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,sum=0;
cin>>n;
for (int i = 1; i <= n;i++)
{
cin >> w[i];
sum += w[i];
}
int v = sum >> 1;
for (int i = 1; i <= n;i++)
for (int j = v; j >= w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
cout << sum - dp[v];
return 0;
}
湖南省第一届大学生计算机程序设计竞赛(HNCPC2005) - 重现
A (1180) : n个人
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=50+10,INF=1e8;
int vis[N],ans[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
while(cin>>n)
{
queue<int> que;
vector<int> ans;
for (int i = 1; i <= n;i++)
{
que.push(i);
}
while(que.size()>2)
{
int t = que.front();
que.pop();
que.push(t);
int tt = que.front();
ans.push_back(tt);
que.pop();
}
for(auto x: ans)
{
cout << x << ' ';
}
cout << '\n';
int a = que.front();
que.pop();
int b = que.front();
que.pop();
if(a>b)
swap(a, b);
cout << a << ' ' << b<<'\n';
}
return 0;
}
B (1181) : 矩阵字符串
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100+10,INF=1e8;
char mp[N][N];
string s;
int dx[8] = {-1, 0, 1, -1, 1, -1, 0, 1}, dy[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
int w, h,len,vis[N][N];
int ansx, ansy;
bool dfs(int x, int y, int dir)
{
int len = s.length();
int xx = x + (len - 1) * dx[dir];
int yy = y + (len - 1) * dy[dir];
if(xx > h || xx <= 0 || yy > w || yy <= 0) return false;
for(int i=1; i<len; i++)
{
x += dx[dir];
y += dy[dir];
if(s[i] != mp[x][y]) return false;
}
return true;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>w>>h)
{
for (int i = 1; i <= h;i++)
{
for (int j = 1; j <= w;j++)
{
cin >> mp[i][j];
}
}
int q;
cin >> q;
while(q--)
{
pii l, r;
cin >> s;
int f = 0;
for (int i = 1; i <= w;i++)
{
for (int j = 1; j <= h;j++)
{
if(mp[j][i]==s[0])
{
for (int k = 0; k < 8;k++)
{
int x = j, y = i;
if(dfs(x, y,k))
{
f = 1;
l = make_pair(x, y);
r = make_pair(x + (s.length() - 1) * dx[k], y + (s.length() - 1) * dy[k]);
break;
}
}
if(f)
break;
}
}
if(f)
break;
}
cout << "(" << l.second << "," << l.first << ")->(" << r.second << "," << r.first << ")\n";
}
}
return 0;
}
C (1182) : 图案的最小变换
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100+10,INF=1e8;
char a[N][N], aa[N][N],b[N][N],aaa[N][N];
int n;
bool check()
{
for (int i = 0; i < n;i++)
{
for (int j = 0; j < n;j++)
{
if(a[i][j]!=b[i][j])
return 0;
}
}
return 1;
}
bool rot90()
{
int tt = n-1;
for (int i = 0; i < n;i++,tt--)
for (int j = 0; j < n;j++)
a[j][tt] = aa[i][j];
if (check())
return 1;
return 0;
}
bool vr()
{
int xx = n-1;
for (int i = 0; i < n;i++,xx--)
for (int j = 0; j < n;j++)
{
a[i][j] = aa[xx][j];
}
if (check())
return 1;
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
while(cin>>n)
{
for (int i = 0; i < n;i++)
{
cin >> a[i];
cin >> b[i];
}
cout << t << ' ';
t++;
if(check())
{
cout << "idt" << '\n';
continue;
}
memcpy(aa, a, sizeof a);
//memcpy(aaa, a, sizeof a);
if(rot90())
{
cout << "rot90" << '\n';
continue;
}
memcpy(aa, a, sizeof a);
if(rot90())
{
cout << "rot180" << '\n';
continue;
}
memcpy(aa, a, sizeof a);
if(rot90())
{
cout << "rot270" << '\n';
continue;
}
memcpy(aa, a, sizeof a);
rot90();
memcpy(aa, a, sizeof a);
if (vr())
{
cout << "vr" << '\n';
continue;
}
memcpy(aa, a, sizeof a);
if(rot90())
{
cout << "vr-rot90" << '\n';
continue;
}
memcpy(aa, a, sizeof a);
if(rot90())
{
cout << "vr-rot180" << '\n';
continue;
}
memcpy(aa, a, sizeof a);
if(rot90())
{
cout << "vr-rot270" << '\n';
continue;
}
cout << "imp" << '\n';
}
return 0;
}
D (1183) : 消除隐藏线
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=50+10,M=1000+10,INF=1e8;
int n, h[M], mmax;
struct stu
{
int l,h,r;
}a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>n)
{
for(int i=1;i<=n;i++)
{
cin>>a[i].l>>a[i].h>>a[i].r;
for(int j=a[i].l;j<a[i].r;j++)
{
h[j]=max(h[j],a[i].h);
}
mmax=max(mmax,a[i].r);
}
for(int i=1;i<=1005;i++)
{
if(h[i]&&h[i]!=h[i-1])
{
cout << i << ' ' << h[i];
if(i+1==mmax)
cout << '\n';
else
cout << ' ';
}
else if(h[i]&&h[i+1]==0)
{
cout << i + 1 << ' '<<0;
if(i+1==mmax)
cout << '\n';
else
cout << ' ';
}
}
for (int i = 0; i < M;i++)
h[i] = 0;
mmax = 0;
}
return 0;
}