目录
A. Shortest Path with Obstacle
F. Array Stabilization (GCD version)
比赛链接
Dashboard - Codeforces Round #731 (Div. 3) - Codeforces
A. Shortest Path with Obstacle
题意
给出三个点A、B、F的二维坐标,问你A和B两点不经过F的最小距离。
思路
首先先算出AB两点之间的举例,判断F是否在中间,如果在就+2,不在就不动。
变量一多我就有点晕,几分钟之后才AC
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<vector>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const int inf=0x3f3f3f3f;
int T,a1,a2,b1,b2,f1,f2,d;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
cin>>T;
while (T--)
{
cin>>a1>>a2>>b1>>b2>>f1>>f2;
d=abs(a1-b1)+abs(a2-b2);
//cout<<d<<" "<<f2<<" "<<min(a2,b2)<<" "<<max(a2,b2)<<endl;
if (a1==b1&&f1==a1&&(f2<=max(a2,b2)&&f2>=min(a2,b2))) d+=2;
if (a2==b2&&f2==a2&&(f1<=max(a1,b1)&&f1>=min(a1,b1))) d+=2;
cout<<d<<endl;
}
return 0;
}
B.Alphabetical Strings
题意
给出一个字符串,判断是否合法,合法是从a开始两边一直有递增的
思路
先确定a的位置,然后去两边双指针去寻找下一个,如果没有那么就是不合法的,最后所有长度都合法,那么就是合法的。
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<vector>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const int inf=0x3f3f3f3f;
string st;
int T,len,pos,l,r;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
cin>>T;
while (T--)
{
cin>>st;
len=st.length();
pos=-1;
for (int i=0;i<len;i++)
if (st[i]=='a') {pos=i;break;}
//找a的位置
l=pos,r=pos;
//双指针
bool boo=true;
if (len==1&&st[0]!='a'||pos==-1) boo=false;
for (int i=2;i<=len;i++)
{
if (l>0&&st[l-1]==char(i+'a'-1)) {l--;continue;}
if (r<len-1&&st[r+1]==char(i+'a'-1)) {r++;continue;}
//两个指针都没有continue 说明没有找到
boo=false;
break;
}
if (boo) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
C. Pair Programming
题意
两个序列要不打乱各自顺序下合并,满足序列中所有不等于0的数字当前小于等于k,k有一个初始值,如果0的话就k+1
思路
也是一个贪心双指针,遇到0就加,反正不会有什么影响,k越多越好;如果碰到不是0的,就判断当前k能不能满足,能的话就指向下一个;不可以的话那么序列是无法满足的
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<vector>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
const int N = 500;
int a[N],b[N],t1,t2,k,n,m,cnt,ans[N],T;
ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const int inf=0x3f3f3f3f;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
cin>>T;
while (T--)
{
cin>>k>>n>>m;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=m;i++) cin>>b[i];
t1=1;t2=1;cnt=0;
bool boo=true;
while (1)
{
if (cnt==n+m) break;
if (a[t1]==0&&t1<=n)
{
ans[++cnt]=a[t1++];
k++;
continue;
}
if (b[t2]==0&&t2<=m)
{
ans[++cnt]=b[t2++];
k++;
continue;
}
//0的情况
if (a[t1]<=k&&t1<=n)
{
ans[++cnt]=a[t1++];
continue;
}
if (b[t2]<=k&&t2<=m)
{
ans[++cnt]=b[t2++];
continue;
}
//不为0的情况
boo=false;
break;
//都没有continue 说明没有办法使得其继续下去
}
if (!boo) cout<<-1;
else for (int i=1;i<=cnt;i++) cout<<ans[i]<<" ";
cout<<endl;
}
return 0;
}
D. Co-growing Sequence
题意
给出一个序列,问你当前要加上多少,满足
思路
我们可以用先去或得到一个tmp=a[i-1] | a[i];这个就是我们需要达到的数字,然后用去异或来得到a[i]还差多少,输出a[i]^tmp,然后这个tmp赋值给a[i],下一次到i+1的时候用得上
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<vector>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const int inf=0x3f3f3f3f;
const int N = 2e5+7;
ll t[40],b,a[N],x;
int T,n,tmp;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
b=1;
for (int i=1;i<=31;i++)
{
b<<=1;
t[i]=b-1;
}
cin>>T;
while (T--)
{
cin>>n;
for (int i=1;i<=n;i++)
cin>>a[i];
cout<<0<<" ";
for (int i=2;i<=n;i++)
{
tmp=(a[i]|a[i-1]);
cout<<(tmp^a[i])<<" ";
a[i]=tmp;
}
cout<<endl;
}
return 0;
}
E. Air Conditioners
题意
k个位置上有空调,温度是t,每隔一个,温度+1,求这个区间内每一处的最小温度
思路
我做的时候不知道怎么处理一个地方,因为这一个地方有很多东西影响,有左边来的也有右边来的,补题的时候才知道,我们只需要扫两遍,左边右边各一遍即可。
先把每一处全部赋值个inf,再把每个地方的空调温度全部复制给数组上。左边扫一遍是处理所有空调向右的影响,这样就不用管我之前所说的,右边扫回来也是同理。看代码吧
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<vector>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const int inf=0x3f3f3f3f;
const int N = 3e5+7;
ll a[N],n,k,T,pos[N];
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
cin>>T;
while (T--)
{
cin>>n>>k;
memset(a,0x3f/2,sizeof(a));
for (int i=1;i<=k;i++) cin>>pos[i];
for (int i=1;i<=k;i++) cin>>a[ pos[i] ];
for (int i=2;i<=n;i++) a[i]=min(a[i],a[i-1]+1);
for (int i=n-1;i>=1;i--) a[i]=min(a[i],a[i+1]+1);
for (int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
return 0;
}
F. Array Stabilization (GCD version)
题意
给出一个序列,每一次操作使得a[i]和a[i+1]取gcd然后给a[i],当越界的时候也就是i=n的时候,a[n]与a[1]取gcd,问至少多少次之后,整个序列相等
思路
我们先来想一想暴力算法,然后再优化。
先枚举次数,从1-n,然后枚举每个区间开始,然后查询的gcd,该时间复杂度是
优化枚举区间长度的GCD:ST表
优化枚举区间长度(次数):二分答案
ST表以前都是用来去min或者max的,但是只需要将其改成gcd即可,学到了。二分答案是因为其有单调性,“不合法”、“不合法”、...、“不合法”、“合法”、...、“合法”
但是我代码...不知道错哪了,求大神解答
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<vector>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const int inf=0x3f3f3f3f;
const int N = 4e5+7;
int lg2[N],f[N][30],n,T,l,r,mid;
inline int query(int l,int r)
{
int w=lg2[r-l+1];
//cout<<"!"<<l<<" "<<r<<" "<<f[l][w]<<" "<<f[r-(1<<w)+1][w]<<endl;
return GCD(f[l][w],f[r-(1<<w)+1][w]);
}
inline void ST()
{
for (int i=n;i>=1;i--)
for (int j=1;i+(1<<j)-1<=n;j++)
f[i][j]=GCD(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
inline void init()
{
for (int i=2;i<=n;i++)
lg2[i]=lg2[i>>1]+1;
}
inline bool check(int k)
{
int tmp=-1;
if (k==0) return true;
for (int i=1;i<=n;i++)
{
int t=query(i,i+k-1);
//cout<<t<<endl;
if (tmp==-1) tmp=t;
else if (tmp!=t) return false;
}
return true;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
cin>>T;
init();
while (T--)
{
cin>>n;
for (int i=1;i<=n;i++) cin>>f[i][0];
for (int i=n+1;i<=2*n;i++) f[i][0]=f[i-n][0];
n<<=1;
ST();
n>>=1;
//cout<<"T="<<T<<endl;
int l=0,r=n,mid;
while(l<r){
//out<<l<<" "<<r<<endl;
mid=(l+r)/2;
if(check(mid)){
r=mid;
}
else{
l=mid+1;
}
}
if(r)r--;
cout<<r<<endl;
}
return 0;
}
/*
INPUT
1
5
5 13 2 10 11
OUTPUT
4
ANSWER
2
*/
G. How Many Paths?
待补
友情链接
Codeforces Round #731 (Div. 3) +382_TheSunspot的博客-CSDN博客
总结
ST(Sparse Table)表,中文名稀疏表,是一种数据结构。
ST表常用于解决可重复贡献问题。
什么是可重复贡献问题?
举例来说:要你求10个数中的最大数,你完全可以先求前6个数的GCD。虽然中间有几个数被重复计算了,但并不影响最后的答案。
常见的可重复贡献问题有:区间最值、区间按位和、区间按位或、区间GCD等。而像区间和这样的问题就不是可重复贡献问题。