3.4-3.10周报
周二天梯训练赛
A
这个题就是每次看到'.',就在它后面放一串英文字符"xixixixi."
L
其实就是看完整过了多少个视频,以及剩下的那个视频有没有播放到第m秒。
J
这个题wa了六发,好离谱,题读错了,其实就是每次都减去当前这个数字里任意一个数位,那我们就能有一个贪心思路,每次都减去最大的那个数,比如876,减去8一定比减去6更优。
点击查看代码
while(n>0){
int nn=n;
int max1=0;
while (nn > 0) {
int d = nn % 10;
nn /= 10;
max1=max(max1,d);
}
n-=max1;
ans++;
}
cout<<ans<<endl;
G
这个题也有坑,也不能算坑,就是我自己不认真读题,题目是选择三个方案中的其中一种,然后一直执行该操作,其实就是三个情况都跑一遍,看哪个最优就行。我第一遍读成了每一次操作都是三选一,也就是hard版的题意。其实就是个简单的贪心。
D
这个题还挺有意思的,我就是直接按照二维前缀和的做法套了个set,这样我就能得到每一个方框能得到的土豆情况,再把这些情况放进set里,是一个及其暴力的做法,但还好,过了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//vector<pair<int,int>>d;
set<pair<int,int>>c[55][55];
set<set<pair<int,int>>>ss;
int a[55][55];
set<int>sx,sy;
int32_t main(){
ios::sync_with_stdio(0);
cin.tie(0) , cout.tie(0);
int n;
cin>>n;
int minx=55,miny=55,maxx=-1,maxy=-1;
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
a[x][y]=1;
//d.push_back({x,y});
sx.insert(x);
sy.insert(y);
minx=min(minx,x);
miny=min(miny,y);
maxx=max(maxx,x);
maxy=max(maxy,y);
}
for(int i=minx;i<=maxx;i++){
for(int j=miny;j<=maxy;j++){
if(a[i][j]==1)
c[i][j].insert({i,j});
if(j>=1)
c[i][j].insert(c[i][j-1].begin(),c[i][j-1].end());
if(i>=1)
c[i][j].insert(c[i-1][j].begin(),c[i-1][j].end());
}
}
for(auto x1:sx){
for(auto x2:sx) {
for (auto y1:sy) {
for(auto y2:sy) {
set<pair<int, int>> e;
//e.insert({d[i].first,d[i].second});
for (auto ee: c[x2][y2]) {
if (x1 >= 1 && y1 >= 1) {
if (c[x1 - 1][y2].count(ee) || c[x2][y1 - 1].count(ee)) {
continue;
} else {
e.insert(ee);
}
} else if (x1 >= 1) {
if (c[x1 - 1][y2].count(ee)) {
continue;
} else {
e.insert(ee);
}
} else if (y1 >= 1) {
if (c[x2][y1 - 1].count(ee)) {
continue;
} else {
e.insert(ee);
}
} else {
e.insert(ee);
}
}
ss.insert(e);
}
}
}
}
cout<<ss.size()<<endl;
return 0;
}
B
这道题其实就是简单的差分前缀和问题,想要每个鸡蛋都达到所需要的温度,不就是初始温度为负的所需要的温度,执行完当前方案后看看是不是所有的鸡蛋都变成了0度以上,只要是就是合理的,然后找到最便宜的方案即可。
点击查看代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int a[110],b[110],c[110];
struct node{
int l,r,k,p;
}d[15];
void solve(long long kk) {
int n,m;
int sum=LLONG_MAX;
int N=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
int l,r,m;
cin>>l>>r>>m;
a[l]+=(-m);
a[r+1]-=(-m);
N=max(N,r);
}
// for(int j=1;j<=N;j++){
// b[j]=b[j-1]+a[j];
// //cout<<j<<" "<<b[j]<<" ";
// }
// cout<<endl;
for(int i=1;i<=m;i++){
cin>>d[i].l>>d[i].r>>d[i].k>>d[i].p;
}
//cout<<"----\n";
for(int i=0;i<=(1<<m)-1;i++){
memset(b,sizeof(b),0);
for(int j=1;j<=N;j++){
c[j]=a[j];
}
int x=i;
int f=0;
int asum=0;
for(int j=1;j<=m;j++){
if(x%2==1){
c[d[j].r+1]-=d[j].k;
c[d[j].l]+=d[j].k;
asum+=d[j].p;
}
//cout<<x%2;
x/=2;
}
//cout<<endl;
for(int j=1;j<=N;j++){
b[j]=b[j-1]+c[j];
//cout<<b[j]<<" ";
if(b[j]<0){
f=1;
}
}
//cout<<endl;
if(f==0)
sum=min(sum,asum);
//cout<<f<<" "<<asum<<endl;
}
cout<<sum<<endl;
return ;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0) , cout.tie(0);
long long T = 1;
//cin >> T ;
for(long long i=1;i<=T;i++) solve(i);
return 0;
}
赛时只过了这几道题,赛后又补了几道题。
I
这个题其实之前做过类似的题,只是我赛时没想起来,要找到这个数有多少个因数,其实就是找质因数,然后求一下组合数,比如54可以分为3个3和1个2,因数就是4*2=8个,选不选这个质因数以及选几个质因数的问题。其实代码的重点就是预处理一下有多少个质因数以及求组合数。
点击查看代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
set<int>s;
int prime[50000];
int f[100010];
void shaishu(int n){
int ans=1;
for(int i=2;i<=n;i++){
if(f[i]==1)
continue;
else{
prime[ans++]=i;
}
for(int j=2;i*j<=n;j++){
f[i*j]=1;
}
}
}
void solve(long long kk) {
int n;
cin>>n;
int sum=1;
for(int i=1;prime[i]<=sqrt(n);i++){
if(n%prime[i]==0){
int ans=0;
while(n){
if(n%prime[i]==0){
ans++;
}
else{
break;
}
n/=prime[i];
}
sum*=(ans+1);
}
}
if(n!=1){
sum*=2;
}
cout<<sum<<endl;
return ;
}
signed main() {
// ios::sync_with_stdio(0);
// cin.tie(0) , cout.tie(0);
long long T = 1;
shaishu(100000);
cin >> T ;
for(long long i=1;i<=T;i++) solve(i);
return 0;
}
H
这个题就是G题的hard版,也就是我一开始读错题的版本,其实就是个dp,只是dp思路有点难想明白。
dp[l][r]l就是左端点,r就是右端点,当长度等于2时,其实可以理解为赋初值,它的值就是两个位置的数字和模3,当长度大于2时就可以由递推式得出,当前这个长度的值是从左边拿两个,从右边拿两个以及左右各一个三种情况得来的,找最大值即可。
最后dp[1][n]就是最后的结果。
点击查看代码
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
int l = j,r = j + i - 1;
if (r > n) continue;
if (l >= r) continue;
if (r - l + 1 == 2) dp[l][r] = (a[l] + a[r]) % 3;
else{
dp[l][r] = max({dp[l][r],(a[l] + a[l + 1]) % 3 + dp[l + 2][r],(a[r] + a[l]) % 3 + dp[l + 1][r - 1],(a[r] + a[r - 1]) % 3 + dp[l][r - 2]});
}
}
}
cout<< dp[1][n] <<endl;
牛客寒假集训营1
A
这个题就是看DFS和dfs是不是当前字符串的子序列。其实很简单了就是遍历一遍就行。
M
每次只能显示6个题,向左和向右移动都只能移动六个题,除非没有题了,就顶到最后一个题,其实我们用7个题就能找到规律,就是有没有余数的问题,有余数就是几个6的二倍,否则就是几个6
G
这个题就是,满a减b,但是优惠券可以叠加,那就是贪心了,看最大可用的优惠券面值是多大,比它更小的就都可以用了。
C
这道题需要知道一个前提就是,这个队伍的排列就是按照办事时间排序,越小的人越先办,那其实就是看工作人员的忍耐度允许这个人插几个人的队,只有这几个被插队的人的不满意度才会增加,那也就是前几个人办完的时间加上这个人的办事时间。
L
这个题其实有很多干扰条件,只需要看光照大地的面积,那就只需要画出来xoy平面的图就可以,灯放在x轴是最优的方案,直接带入求面积就可以了。
B
这道题其实主要就是想明白一个点,最多也就是填三个点(2,0),(1,-1)(1,1),这三个点就能让无法逃脱,还有一点就是不只有直线,相邻的斜对角也会把它堵住。
点击查看代码
#include "bits/stdc++.h"
using namespace std;
#define int long long
set<pair<int, int>> s;
void solve() {
s.clear();
int n;
cin >> n;
int ans0 = 2, ans1 = 2;
for (int i = 0; i < n; i++) {
int r, c;
cin >> r >> c;
s.insert({r, c});
if (c <= 0) {
ans0 = 1;
}
if (c >= 0) {
ans1 = 1;
}
}
for (auto e : s) {
int r=e.first;
int c=e.second;
for (int i = -1; i < 2; i++) {
if (s.count({r ^ 3, c + i})) {
if (c < 0) {
ans0 = 0;
}
if (c > 0) {
ans1 = 0;
}
}
}
}
int ans = 3 - s.count({2, 0}) - s.count({1, -1}) - s.count({1, 1});
cout << min(ans, ans0 + ans1) << '\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0) , cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
天梯选拔2
L1-2
把式子化简一下就可以,然后就是注意=的情况,wa了一发
L1-3
直接带入计算,注意输出格式,两位小数。
L1-4
这道题题意比较绕,其实就是先算出来单属性打双属性,题意比较绕。
L1-5
这个题真的很离谱,题意没读懂,因为同一位置的红石重叠但不影响,所以其实可以把路径拉直进行分析,那几个点的作用就是求路径长,红石信号可以发15,每个红石最低能量值是吗,那也就是每一个红石的合法区间是(15-m)*2+1,贪心的放置,特判一下m为0也就是不用放置,m为15所有点都要放置,注意long long
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int x[10010],y[10010];
int32_t main(){
int n,m;
cin>>n>>m;
int sum=0;
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
if(i>1){
sum+=abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
}
}
sum++;
if(m==15){
cout<<sum<<endl;
return 0;
}
if(m==0){
cout<<0<<endl;
return 0;
}
m=2*(15-m)+1;
//cout<<sum<<" "<<m<<endl;
if(sum%m==0){
cout<<sum/m<<endl;
}
else{
cout<<sum/m+1<<endl;
}
return 0;
}
L1-6
就是个暴力查找,注意区分代码内还是代码外就行
L1-7
这个题注意给的袋子高度是按从小到大的顺序给的,那就很简单了,在跨度最大的几个位置拆开,内部跨度就会减小,也就是求个跨度总和,减去最大的几个跨度。
L1-8
这题就是单纯找规律,看到就感觉有前缀和那味,只是运算符不一样,然后暴力处理出来找规律。
L2-2
这个题就是个树上的搜索,加粗的那行字已经保证了是树,需要合成的那个精灵就是根节点,不需要合成的精灵的叶子结点,存单向边进行搜索就可以。需要的经验值就是边权,跑过的边的权值求和就行。赛时也出了思路,但是有个坑点,升1级不需要经验,我在计算每条边的权值,也就是升级经验的时候没考虑这个情况,赛时一直没出。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int>d[100010];
map<pair<int,int>,int>mp;
int sum=0;
int f[100010];
int huafei(int x,int y){
if(y==1){
return 0;
}
y--;
if(x==1)
return (1+y-1)*(y-1)/2+1;
else if(x==2)
return (2+(y-1)*2)*(y-1)/2+1;
else
return (5+(y-1)*5)*(y-1)/2+1;
}
void dfs(int x){
for(auto e:d[x]){
sum+=mp[{x,e}];
dfs(e);
}
}
int32_t main(){
int X,m;
cin>>X>>m;
for(int i=1;i<=m;i++){
int a,b,c,e;
cin>>a>>b>>c>>e;
mp[{a,b}]=huafei(c,e);
d[a].push_back(b);
}
dfs(X);
cout<<sum<<endl;
return 0;
}
L2-3
这个题就是状态压缩,cnt[x][y],x存的就是字符串的数位和,y就是这个字符串的长度是奇数还是偶数。既然要两个字符串补在一起,那我们就先让所有的字符串作为左边的字符串,想要两个评起来的左右两边和相等,那就先遍历这个分割线的位置在哪,先将左边的字符串分为两半,右边的字符串直接补在左边字符串的右半个,如果划分的位置左边和比右边和小,那一定不合法,合法的情况一定能算出左半个和右半个的差,那就是右边那个字符串的和的值,刚刚预处理的时候已经将这个状态存起来了。然后再让所有的字符串作为右边的字符串处理一下。这里注意,从最左边和最右边的分割其实就是整个字符串,左边处理过右边就不用处理了,不然情况会重叠。
点击查看代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
string s[200010];
int cnt[200010][5];
int sums[200010];
int js(string s){
int sum=0;
for(int i=0;i<s.length();i++){
sum+=(s[i]-'0');
}
return sum;
}
void solve(long long kk) {
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
sums[i]=js(s[i]);
cnt[js(s[i])][s[i].length()%2]++;
}
int ans=0;
for(int i=1;i<=n;i++){
int suml=0,sumr;
for(int j=0;j<s[i].length();j++){
suml+=(s[i][j]-'0');
sumr=sums[i]-suml;
if(suml<sumr){
continue;
}
else{
ans+=cnt[suml-sumr][s[i].length()%2];
}
}
}
for(int i=1;i<=n;i++){
int sumr=0,suml;
for(int j=s[i].length()-1;j>0;j--){
sumr+=(s[i][j]-'0');
suml=sums[i]-sumr;
if(suml>sumr){
continue;
}
else{
ans+=cnt[sumr-suml][s[i].length()%2];
}
}
}
cout<<ans<<endl;
return ;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0) , cout.tie(0);
long long T = 1;
//cin >> T ;
for(long long i=1;i<=T;i++) solve(i);
return 0;
}

浙公网安备 33010602011771号