题目链接
https://codeforces.com/contest/1547
A 题意
三个二维点,不经过三号点一二号点最短路
A 思路
除非连成线且三号在正中,否则就是横纵坐标求差的绝对值和,如果连线,答案加2
A 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=200505;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
int ans;
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
int x1,y1,x2,y2,x3,y3;
cin>>x1>>y1>>x2>>y2>>x3>>y3;
int t=abs(x1-x2)+abs(y1-y2);
if(x1==x2&&x1==x3&&y3!=max(max(y1,y2),y3)&&y3!=min(min(y1,y2),y3)) t+=2;
if(y1==y2&&y1==y3&&x3!=max(max(x1,x2),x3)&&x3!=min(min(x1,x2),x3)) t+=2;
cout<<t<<endl;
}
}
B 题意
a-z顺序生成一个串,每次只能在之前基础上插头插尾,给你一堆串,问你是否是按这个办法生成的
B 思路
假定长为x,那么1-x的字母都必须出现一次。
之后定位a,向左向右各扫一遍,都为递增即正确。
B 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=205;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
int ans;
int cnt[maxn];
void solve(){
string s;
cin>>s;
memset(cnt,0,sizeof cnt);
for(auto i:s)
cnt[i-'a']++;
int index;
for(int i=0;i<s.size();i++){
if(cnt[i]!=1){
cout<<"NO"<<endl;
return;
}
}
for(int i=0;i<s.size();i++){
if(s[i]=='a'){
index=i;break;
}
}
for(int i=index;i;i--){
if(s[i]<s[i-1]) continue;
else{
cout<<"NO"<<endl;
return ;
}
}
for(int i=index;i<s.size()-1;i++){
if(s[i]<s[i+1]) continue;
else{
cout<<"NO"<<endl;
return ;
}
}
cout<<"YES"<<endl;
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
solve();
}
}
C 题意
两个序列,要求你合并他们(不改变两个序列原顺序)。有一个初值k,要求新的序列中,每次遇0,k++,否则要求k大于等于遇到的数。输出这个合并序列或者说不存在
C 思路
双指针贪心,有0就放,全为数字就放较小的。
C 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=205;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
int b[maxn];
int ans;
int cnt[maxn];
void solve(){
cin>>k>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
int p1=1,p2=1;
vector<int>v;
while(p1<=n&&p2<=m){
if(p1<=n&&a[p1]==0){
v.push_back(0);
p1++;
continue;
}
if(p2<=m&&b[p2]==0){
v.push_back(0);
p2++;
continue;
}
if(a[p1]<b[p2]){
v.push_back(a[p1]);
p1++;
continue;
}
else{
v.push_back(b[p2]);
p2++;
continue;
}
}
while(p1<=n){
v.push_back(a[p1]);
p1++;
}
while(p2<=m){
v.push_back(b[p2]);
p2++;
}
for(auto i:v){
if(i==0){
k++;
continue;
}
if(i>k){
cout<<-1<<endl;
return;
}
}
for(auto i:v) cout<<i<<' ';cout<<endl;
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
solve();
}
}
D 题意
若一个序列满足所有 a[i]&a[i+1]=a[i]
,&为二进制或,成为growing数列,给你一个数列,且一个字典序最小的数列b,b[i]^a[i]
数列growing。
D 思路
字典序最小,那么显然越晚处理越好,所有从左向右扫,扫到不满足的就处理a[i+1],对于处理,就是把a[i]有1,a[i+1]没有1的位置异或1,我们需要额外操作来顺道让后面的i+2等等满足吗?不需要,字典序最小,那样的话一定答案更劣。所以就是相当于一个二进制模拟了,熟悉二进制操作就行。
D 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=200505;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
int ans[maxn];
void deal(int &a,int &b,int index){
int now=1;
while(now<=a){
if((now&a)&&!(now&b)){
b^=now;
ans[index]^=now;
}
now<<=1;
}
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
cin>>n;
memset(ans,0,sizeof ans);
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<n;i++){
if((a[i]&a[i+1])!=a[i]){
deal(a[i],a[i+1],i+1);
}
}
for(int i=1;i<=n;i++)
cout<<ans[i]<<' ';
cout<<endl;
}
}
E 题意
一维数组有空调,第i个空调会将他的格子位置设成温度t[i],远离一个格子是t[i]+1,以此类推。每个格子的实际温度是所有空调在这个地方的温度取最小值,输出每个格子的实际温度
E 思路
两个数组初值全为inf。从左到右从右到左分别扫一遍,扫的过程中如果没空调就是上个格子温度+1,否则就是和新空调取个min。两边扫完每个格子取个min即可。
E 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=300005;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn],t[maxn];
int le[maxn],rt[maxn];
vector<int>ans;
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
cin>>n>>k;
for(int i=0;i<=n+5;i++)
le[i]=rt[i]=inf;
ans.clear();
for(int i=1;i<=n;i++) a[i]=0;
for(int i=1;i<=k;i++){
int t;
cin>>t;
a[t]=i;
}
for(int i=1;i<=k;i++) cin>>t[i];
int dis=0;
for(int i=1;i<=n;i++){
if(!a[i]){
le[i]=le[i-1]+1;
}
else{
if(t[a[i]]<le[i-1]+1){
le[i]=t[a[i]];
}
else
le[i]=le[i-1]+1;
}
}
for(int i=n;i;i--){
if(!a[i]){
rt[i]=rt[i+1]+1;
}
else{
if(t[a[i]]<rt[i+1]+1){
rt[i]=t[a[i]];
}
else
rt[i]=rt[i+1]+1;
}
}
for(int i=1;i<=n;i++)
cout<<min(le[i],rt[i])<<' ';
cout<<endl;
}
}
F 题意
数组进行操作,每次操作将a[i]变成a[i]与a[i+1]的gcd。如果是a[n]就是和a[1]取。问多少次后全相同
F 思路
容易发现
- 答案有单调性,且范围为0-n
- 操作了i次,相当于原数组i个相邻数取gcd.
二分答案,每次枚举位置判断区间gcd,区间gcd可以用ST表求。
复杂度
O
(
n
∗
l
o
g
2
n
)
O(n*log^2n)
O(n∗log2n)
F 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=200505;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
int ans;
unordered_map<int,bool>mp;
int ST[maxn][20];//ST ij means the max number form i to i+pow 2 j
//20 is log 2 maxn,maxn 1000000 ok
void preST(int len){
for(int i=1;i<=len;i++)
ST[i][0]=a[i];
int t=log(len)/log(2)+1;
for(int j=1;j<t;j++)
for(int i=1;i<=len-(1<<j)+1;i++)
ST[i][j]=__gcd(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
}
int query(int l,int r){
int k=log(r-l+1)/log(2);//pow 2 k is lower than l-r+1
return __gcd(ST[l][k],ST[r-(1<<k)+1][k]);
}
bool check(int k){
mp.clear();
int cnt=0;
for(int i=1;i<=n;i++){
int t;
if(i+k-1<=n)
t=query(i,i+k-1);
else
t=__gcd(query(i,n),query(1,k-n+i-1));
if(!mp[t]){
mp[t]=1;
cnt++;
}
if(cnt>1) return 0;
}
return cnt;
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
preST(n);
int l=0,r=n,mid;
while(l<r){
mid=(l+r)/2;
if(check(mid)){
r=mid;
}
else{
l=mid+1;
}
}
if(r)r--;
cout<<r<<endl;
}
}
G 题意
有自环有向图,输出1号点对每个点的可达情况,其中
- 0 不可达
- 1 唯一可达
- 2 多种方案可达
- -1 无穷方案可达
G 思路
SCC缩点,拓扑排序+dp,不可达就是拓扑序在1之前,也就是scc编号在1之后。唯一可达就是传递方案最后dp值为1,多种可达就是传递方案dp为>1数字。无穷可达就是1到它的传递路径上途径某个size大于1的SCC块或者某个自环点,这个情况把dp设成inf,传递时直接相等不要加和。细节很多。
官方题解有别的做法,等待更新。
G 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=1000005;
const int maxe=1000005;
const int inf=0x3f3f3f3f;
int n,m;
int dfn[maxn],low[maxn],dfncnt;
int in_stack[maxn];
int scc[maxn],sc;
int sz[maxn];
vector<int>p[maxn];
int cnt;
int head[maxe];
int ans[maxn];
struct Edge{
int next;
int to;
int form;
int dis;
} edge[maxe];
bool it[maxn],it_scc[maxn];
int in[maxn];
vector<int>e[maxn];
int sc_1;
void init(){
memset(head,-1,sizeof(ll)*(n+15));
memset(ans,0,sizeof(ll)*(n+15));
memset(sz,0,sizeof(ll)*(n+15));
memset(it,0,sizeof(ll)*(n+15));
memset(it_scc,0,sizeof(ll)*(n+15));
memset(in,0,sizeof(ll)*(n+15));
memset(dfn,0,sizeof(ll)*(n+15));
cnt=0;sc=0;dfncnt=0;
for(int i=0;i<n+15;i++)e[i].clear();
}
void add(int u,int v,int w){
edge[cnt].dis=w;
edge[cnt].to=v;
edge[cnt].form=u;
edge[cnt].next=head[u];
head[u]=cnt++;
}
stack<int>sa;
void tarjan(int u) {
low[u] = dfn[u] = ++dfncnt;
sa.push(u); in_stack[u] = 1;
for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (in_stack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
++sc;
while (1) {
int now=sa.top();
sa.pop();
if(now==1)sc_1=sc;
if(it[now])it_scc[sc]=1;
scc[now] = sc;
sz[sc]++;
p[sc].push_back(now);
in_stack[now] = 0;
if(now==u){
break;
}
}
}
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
cin>>n>>m;
init();
while(m--){
int u,v;
cin>>u>>v;
if(u==v)
it[u]=1;
else
add(u,v,0);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i);
}
for(int i=0;i<cnt;i++){
if(scc[edge[i].to]!=scc[edge[i].form]){
e[scc[edge[i].form]].push_back(scc[edge[i].to]);
in[scc[edge[i].to]]++;
}
}
ans[sc_1]=1;
for(int i=1;i<=sc;i++)
if((sz[i]>1||it_scc[i])) ans[i]=-inf;
for(int i=sc;i>sc_1;i--)
ans[i]=0;
for(int i=sc_1;i>=1;i--){
for(auto y:e[i]){
if(ans[i]<0)
ans[y]=-inf;
else if(ans[i]==0){
ans[y]=0;
}
else{
if(ans[y]<2)
ans[y]+=ans[i];
}
}
}
for(int i=1;i<=n;i++)
if(!ans[scc[i]]) cout<<0<<' ';
else if(ans[scc[i]]==1) cout<<1<<' ';
else if(ans[scc[i]]>1) cout<<2<<' ';
else cout<<-1<<' ';
cout<<endl;
}
}