2022.6.15练题
早上七点打开cf,做了昨天的div4,花了一上午才做完并且写完题解。
链接:https://codeforces.com/contest/1692
A
顺序比较即可,O(N)。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5; int a[maxn]; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t; cin>>t; while(t--){ int ans=0; for(int i=1;i<=4;i++) cin>>a[i]; for(int i=2;i<=4;i++){ if(a[i]>a[1]) ans++; } cout<<ans<<"\n"; } return 0; }
B
S有一个有n个元素的数组a,一步操作包括选两个不同的下标i和j,再将ai和aj移除出数组,当数组里面没有重复数字的时候,输出最终数组的大小
输入
t个样例
n(原数组的长度)
a1~an(数组元素)
输出
最终数组的最大size
用一个set存没有重复的数字,然后模拟样例,可知可分为(n-s.size()%2)==1和==0两种情况,abbbccc,abbbcccc这样列举就得出结论了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; set<int> s; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t; cin>>t; while(t--){ s.clear(); int n; cin>>n; int x; for(int i=0;i<n;i++){ cin>>x; s.insert(x); } int k=s.size(); int tem=n-k; if(tem%2==1) cout<<k-1<<"\n"; else cout<<k<<"\n"; } return 0; }
C(象在哪里)
两条"#"的交汇点
O(N^2)暴力即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef double db; char s[9][9]; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t; cin>>t; while(t--){ int x=0,y=0; for(int i=1;i<=8;i++){ for(int j=1;j<=8;j++){ cin>>s[i][j]; } } for(int i=2;i<=7;i++){ for(int j=2;j<=7;j++){ if(s[i-1][j-1]=='#'&&s[i-1][j+1]=='#'&&s[i+1][j-1]=='#'&&s[i+1][j+1]=='#') x=i,y=j; } } cout<<x<<" "<<y<<"\n"; } return 0; }
D(钟)
HH:MM在加无数次x分钟后,求回文子串的个数
思路:打表得到从00:00开始的回文串的时间(min),然后求HH:MM代表的时间
#include<bits/stdc++.h> using namespace std; typedef long long ll; set<string> ss; set<int> t; string s; void init(){ ss.insert("00:00");//0 ss.insert("01:10");//70 ss.insert("02:20");//140 ss.insert("03:30");//210 ss.insert("04:40");//280 ss.insert("05:50");//350 ss.insert("10:01");//601 ss.insert("11:11");//671 ss.insert("12:21");//741 ss.insert("13:31");//811 ss.insert("14:41");//881 ss.insert("15:51");//951 ss.insert("20:02");//1202 ss.insert("21:12");//1272 ss.insert("22:22");//1342 ss.insert("23:32");//1412 } int a[5]={600,60,0,10,1};//对应的时间 int times[16]={70,140,210,280,350,601,671,741,811,881,951,1202,1272,1342,1412};//init() int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); init(); int test; cin>>test; while(test--){ t.clear(); cin>>s; int x; cin>>x; int fg=0; int ans=0; for(int i=0;i<5;i++) fg+=(int)(s[i]-'0')*a[i]; for(int i=0;i<=10000;i++){ t.insert(fg); fg+=x; fg%=1440;//去循环 } for(auto i:t){ for(int j=0;j<16;j++){//times.size() if(times[j]==i) ans++; } } cout<<ans<<"\n"; } return 0; }
F(读错题目了)
开始以为相加是三位数,实际上是三个不同下标的数加起来位数是3,那么只关心末位即可,223442就相当于是2,然后这样以后v.size()<=30,O(N+30^3)的复杂度,不足1e7,可行。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t; cin>>t; while(t--){ int n; cin>>n; vector<int> v; int digit[10]={}; for(int i=0;i<n;i++){ int x; cin>>x; digit[x%10]++; } for(int i=0;i<10;i++){ for(int j=0;j<min(digit[i],3);j++){ v.push_back(i); } } int m=v.size(); bool fg=false; for(int i=0;i<m;i++){ for(int j=i+1;j<m;j++){ for(int k=j+1;k<m;k++){ if((v[i]+v[j]+v[k])%10==3){ fg=true; break; } } } } if(fg) cout<<"YES"<<"\n"; else cout<<"NO"<<"\n"; } return 0; }
G(2^式的排序)
给一个长度为n的a数组和一个整数k,找到i这个下标(1<=i<=n-k),子数组[ai……ai+k]有以下性质:(子数组长度为k+1)
如果你用第i个元素乘以1<<(i-1),那么子数组就是严格单调递增的。
输入
t个样例
n(数组长度) k(子数组长度-1)
a1~an
输出
下标满足条件的数量
实际上就是判断a[i]和2*a[i+1]的关系,用一个b数组来表示,b[i]==1就说明a[i]<2*a[i+1],b[i]==0就说明a[i]>=2*a[i+1],先算从0~k,然后从k~n-1,注意要减去重复的。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+30; int a[maxn]; int b[maxn]={}; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t; cin>>t; while(t--){ int n,k; cin>>n>>k; for(int i=0;i<n;i++) cin>>a[i]; for(int i=0;i<n-1;i++){ b[i]=(a[i]<2*a[i+1]);//只需判断a[i]和2*a[i+1]的关系 } int tem=0,ans=0; for(int i=0;i<k;i++) tem+=b[i]; //从开始到k if(tem==k) ans++; for(int i=k;i<n-1;i++){ tem+=b[i]; tem-=b[i-k];//去掉重复的 if(tem==k) ans++;//满足就ans++; } cout<<ans<<"\n"; } return 0; }
E:(二进制双端队列)
S有一个长为n的只有0 1的数组。在一步操作中,他可以移走开头或者最后一个数组元素。问是最小的操作数,使得数组的和为s。
输入
t个样例
n s(数组长度 需要的数组元素和)
a1~an
输出
最小操作步数
先预处理前缀和使得能够O(1)求得a[l]+……a[r],然后再二分,l=i,r=n-1,用一个pos记录下标,ans=min(ans,n-(pos-i+1));还要写一个pd函数,看[l,r]这段数组元素之和与s之间的关系。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll inf=1e14+30; ll pd(int l,int r,vector<ll>& p){//前缀和 return p[r]-(l?p[l-1]:0); } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t; cin>>t; while(t--){ int n,s; cin>>n>>s; vector<ll> a(n),p(n); for(int i=0;i<n;i++){ cin>>a[i]; p[i]=a[i]; if(i) p[i]+=p[i-1];//前缀和 } ll ans=inf; for(int i=0;i<n;i++){ int l=i,r=n-1; int pos=-1; while(l<=r){ int mid=(l+r)>>1; if(pd(i,mid,p)<=s){//l右移 pos=mid; l=mid+1; } else r=mid-1; } if(pos==-1||pd(i,pos,p)!=s) continue; ans=min(ans,(ll)(n-(pos-i+1))); } if(ans==inf) cout<<"-1"<<"\n"; else cout<<ans<<"\n"; } return 0; }
H(赌博)
M在赌场。赌场的游戏是这样的。
在每一轮赌博以前,玩家选择一个在1到1e9之间的数字。在那以后,一个有1e9个面的骰子被扔出,出现了一个从1到1e9的随机数。如果这个玩家猜对了的话他们的钱就会加倍,否则会减半。
M预测未来,知道接下来n轮骰子会转向那个数字。他会挑选三个数字(a,l,r)。他会玩r-l+1轮。在这些轮中的每一轮,他会猜相同的数字a。在l轮之前他有1美元。
M问你来决定a,l,r,使得他在最后赚最多的钱。
输入
t个样例
n(游戏轮数)
x1~xn
实际上就是选择一个区间[l,r]使得里面(一样的数的个数-不一样的数的个数)max。
黑科技:map<int,vector<int>> p;
#include<bits/stdc++.h> using namespace std; typedef long long ll; void solve(){ int n; cin>>n; map<int,vector<int>> p; vector<int> x(n); for(int i=0;i<n;i++){ cin>>x[i]; p[x[i]].push_back(i); } int a=x[0],l=0,r=1,ans=1; for(auto [b,q] : p){ int min=0,k=q[0];//min左端点 for(int j=0;j<int(q.size());j++) { int i=q[j]; int cur=j-(i-j); if(cur<min) { min=cur; k=i; } int res=cur+1-min;//区间长度 if(res>ans) { ans=res; a=b; l=k; r=i+1; } } } cout<<a<<" "<<l+1<<" "<<r<<"\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t; cin>>t; while(t--){ solve(); } return 0; }
下午准备做一套gym,结果睡了三个小时…………
20:00-0:30 2020-2021 ICPC - Gran Premio de Mexico - Repechaje
链接:https://codeforces.com/gym/102966
A A的棋盘(数学推公式)
A总是想办法享受乐趣。她把2*2方格中有两个白色两个黑色块叫做P石材配置。要保证每个2∗2的矩阵都有两个黑石头和两个白石头,问有多少种摆放方式?
公式:(1<<m)+(1<<n)-2
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); ll n,m; cin>>n>>m; //cout<<2*(n*m-1)<<"\n"; if(n<2||m<2){ cout<<"0"<<"\n"; } else cout<<(1ll<<m)+(1ll<<n)-2<<"\n"; return 0; }
L(让我们来数F)(数论题,分解质因数)
有多少与A、B不同的素数被乘在一起来获得A*B?
就是求 A , B的共同质因数
对于共同质因数的标记,使用 unordered_map 就可以了,主要的还是欧拉筛的知识。
注意maxn的范围<sqrt(1e7),开始用的1e4 TLE*6
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3200; inline ll read(){ ll x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int cnt; int vis[maxn],pri[maxn]; void Euler(int n){//Oula for(int i=2;i<=n;i++) { if(!vis[i]) pri[++cnt]=i; for (int j=1;j<=cnt;j++) { if(i*pri[j]>n) break; vis[i*pri[j]]=true; if(i%pri[j]==0) break; } } } unordered_map<int, bool> visn; void cal(int x){ for(int i=1;i<=cnt;i++){ if(x%pri[i]==0){ visn[pri[i]]=1; while(x%pri[i]==0) x/=pri[i]; } } if(x>1) visn[x]=1; } int main(){ int t=(int)read(); Euler(maxn); while(t--){ int a=(int)read(); int b=(int)read(); visn.clear(); cal(a); cal(b); printf("%d\n",visn.size()); } return 0; }
K(厨余垃圾)(英语阅读理解题)
有n个面包,m口锅,每口锅中都装了一定体积的汤,要将汤淋在面包上,面包也有体积,一体积汤能淋一体积面包。一次淋面包的操作必须要将整个面包都淋上汤,若锅中剩余汤的体积不足以将整个面包都淋上,则将这个锅中的汤都倒掉。
O(N)简单模拟,难点在于看懂题目
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e3+30; int a[maxn],b[maxn]; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n,m; cin>>n>>m; ll ans=0; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=m;i++) cin>>b[i]; for(int i=1;i<=n;i++){ if(b[i]<a[i]) continue; else if(b[i]>=a[i]) ans+=(b[i]-a[i]); } if(n==m) cout<<ans<<"\n"; else if(m>n){ for(int i=n+1;i<=m;i++) ans+=b[i]; cout<<ans<<"\n"; } return 0; }
G(G碰撞)(规律题)
G有以下行为:
1.最初,他们指在一个方向(左:0 右:1)
2.没有障碍时,他们在一个方向继续前进
3.如果两个G相撞,他们会立刻改变他们的方向
4.当G达到平台的末端,它就输了
结论:无论怎么撞,最终都会有一辆车子走的是他自己的路程或者别人的路程,取向右的最大和向左的最大即可。
即 if(y) ans=max(ans,l-x);
else ans=max(ans,x);
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef double db; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); ll l,n; cin>>l>>n; ll ans=0; for(int i=1;i<=n;i++){ ll x,y; cin>>x>>y; if(y) ans=max(ans,l-x); else ans=max(ans,x); } cout<<ans<<"\n"; return 0; }
C(CLETS巡逻队)(组合数学)
CLETS正在研究一种新的方法来组织他们的追随者的巡逻,这样他们就不可能预测某个英俊的英国间谍会潜入他们的基地。为此,当一个追随者到达一个岗位时,计算机将随机选择该追随者下一个岗位。通过一些分类手段,我们获得了计算机用来选择下一步将追随者送往何处的概率分布。你的任务是利用这些信息来确定每一个岗位上都有一名警卫在M步之后到达那里的可能性,这样间谍就可以规划到CLETS的最安全路线。
一个步骤被定义为从一个岗位移动到另一个岗位,或者在同一岗位上等待,如果计算机决定这样做的话。卫兵在第一根柱子上开始轮班。
输入
我们感兴趣的岗位数量和步骤数量。
一个M*M的矩阵
概率跳过,不知道怎么算概率的,样例是什么意思…………
H(H训练)(数学,推理公式)
棉花糖M收养了一群超级聪明的仓鼠。由于M是认真负责的,他无聊的时候就训练他的仓鼠朋友。训练的规则如下:
1.M分了N^2的纸牌(从1~N^2)
2.M有一个口哨来提醒仓鼠是时候该走了。在那个时刻,仓鼠们各自拿起一张牌,用这N张纸牌组成
一条线。
3.这条线可能是被认为失败或者成功的,但是动物们都很聪明,永远不会输。
4.要取得成功,该行中的每张牌上的数字都必须大于或等于左侧的所有数字。
5.完成并评估线路后,仓鼠将卡片交回,并为下一轮做好准备。
为了估计可能需要的时间,他想知道有多少有效配置。
即给一个n,从1~n中选出n个数(可重复选)组成长度为n的非降序数组。
猜公式C(n,2*n-1)
证明:

#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll maxn=2e5+30; const ll mod=1e9+7; ll fa[maxn],fb[maxn]; ll quickpow(ll a,ll b){//快速幂 ll ans=1; while(b){ if(b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } ll Cal(ll n,ll k){ if(n<0||k<0||k>n) return 0; return fa[n]*fb[k]%mod*fb[n-k]%mod; } void init(){ fa[0]=1; fb[0]=1; for(int i=1;i<=maxn-1;i++){ fa[i]=fa[i-1]*i%mod; fb[i]=quickpow(fa[i],mod-2)%mod; } } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); //C(n,2*n-1) int t; cin>>t; init(); while(t--){ ll n; cin>>n; cout<<Cal(2*n-1,n)<<"\n"; } return 0; }
F(数学,推公式,奥数)
存在一个如上图所示的有五个房间的房子,每个房子里有n * n个格子,
求该图中所有格子对之间的曼哈顿距离总和。
推公式

#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; int main(){ ll n; while(scanf("%lld",&n)!=EOF){ ll ans=((n-1)*n*n/2-(n-1)*n%mod*(2*n-1)/6)%mod; ll a=(2*n*n*ans)%mod; ll b=((n*n%mod*n%mod*n%mod*(n+1)/2)%mod+(n*(2*ans%mod*n%mod+n*n*n*(n-1)/2))%mod)%mod; ll c=(b+(n*n)%mod*(n*n)%mod*n)%mod; ll d=(((n*n)%mod*(n*n)%mod*(n+1))%mod+((n-1)*(n*n)%mod*(n*n)%mod)%mod)%mod; ll anss=((a*5)%mod+b*4%mod+c*2%mod+d*4%mod)%mod;//乘以对应的数量 printf("%lld\n",anss); } return 0; }
还有一道质因数分解的D,明天再补(已经00:49了)(QAQ)

浙公网安备 33010602011771号