Educational Codeforces Round 102 (Rated for Div. 2)
CF1473A
显然要么是初始整个序列就都小于\(d\),否则大于\(d\)的需要变成最小值加上次小值。判断一下即可。
code:
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,k,x,y,z,t,a[139],d,maxn;
int main(){
register int i;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&d);maxn=0;
for(i=1;i<=n;i++) scanf("%d",&a[i]),maxn=max(maxn,a[i]);
sort(a+1,a+n+1);
if(a[1]+a[2]<=d||maxn<=d) printf("YES\n");
else printf("NO\n");
}
}
CF1473B
将大的串不断扩展,直到扩展到可以或超过\(\frac{m^2}{gcd(n,m)}\)就判断无解。
code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,m,flag=0;
string a,b,c;
int main(){
register int i;
scanf("%d",&t);
while(t--){
cin>>a>>b;n=a.size();m=b.size();
if(n>m) swap(n,m),swap(a,b);
c=b;flag=0;
for(i=1;i<n/__gcd(n,m);i++) c+=b;
for(i=0;i<c.size();i++){
if(c[i]!=a[i%n]){flag=1;break;}
}
if(flag) printf("-1\n");
else cout<<c<<endl;
}
}
CF1473C
手推一下可以发现,无论如何\(p\)与\(a\)的前\(2\times k-n\)是一样的,而后面那部分不管怎么动逆序对数都不变,所以后面的将字典序调到最大即可。
code:
#include<cstdio>
using namespace std;
int n,m,k,x,y,z,f[200039],t;
int main(){
register int i;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(i=1;i<2*k-n;i++) f[i]=i;f[2*k-n]=k;
for(i=2*k-n+1;i<=k;i++)f[i]=f[i-1]-1;
for(i=1;i<=k;i++) printf("%d ",f[i]);printf("\n");
}
}
CF1473D
因为操作只有加一减一,所以不同的个数就是最大值减去最小值加一,线段树或st表维护一下即可。
code:
#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define CI const int &
using namespace std;
int n,m,k,x,y,z,t,a[200039],f2[800039],f1[800039],ans1,ans2,ans3,ans4;
char _s;
inline void js(int l,int r,int now){
if(l==r){f1[now]=f2[now]=a[l];return;}
int m=l+r>>1;js(l,m,now<<1);js(m+1,r,now<<1|1);
f1[now]=min(f1[now<<1],f1[now<<1|1]);
f2[now]=max(f2[now<<1],f2[now<<1|1]);
}
inline int find1(int x,int y,CI l=0,CI r=n,CI now=1){
if(x>y) return 0;
if(x<=l&&r<=y) return f1[now];
int m=l+r>>1,f1=1e9,f2=1e9;
if(x<=m) f1=find1(x,y,l,m,now<<1);
if(y>m) f2=find1(x,y,m+1,r,now<<1|1);
return min(f1,f2);
}
inline int find2(int x,int y,CI l=0,CI r=n,CI now=1){
if(x>y) return 0;
if(x<=l&&r<=y) return f2[now];
int m=l+r>>1,f1=-1e9,f2=-1e9;
if(x<=m) f1=find2(x,y,l,m,now<<1);
if(y>m) f2=find2(x,y,m+1,r,now<<1|1);
return max(f1,f2);
}
int main(){
//freopen("1.in","r",stdin);
register int i;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
_s=getchar();
while(_s!='+'&&_s!='-') _s=getchar();
a[i]=a[i-1]+(_s=='+'?1:-1);
}
js(0,n,1);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if(y==n){ans1=find2(0,x-1);ans2=find1(0,x-1);printf("%d\n",ans1-ans2+1);continue;}
ans1=find2(0,x-1),ans2=find2(y+1,n),ans3=find1(0,x-1),ans4=find1(y+1,n);
ans1=max(ans1,ans2-(a[y]-a[x-1]));ans3=min(ans3,ans4-(a[y]-a[x-1]));
printf("%d\n",ans1-ans3+1);
}
}
}
CF1473E
考虑转化一下题意,求一条路径最小权值,最大值不算,最小值算两遍。求\(1\)到每个点最小权值。
再次转化题意:求一条路径最小权值,可以有一个值不算,一个值算两遍。可以发现,如果要答案最小,那么一定是最大值不算,最小值算两遍
那么跑堆优化dj即可。
code:
#include<cstdio>
#include<cstring>
#include<queue>
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
using namespace std;
int n,m,k,x,y,z,flag[200039][2][2];
struct yyy{int to,w,z;}tmp;
struct ljb{
int head,h[200039];yyy f[400039];
inline void add(int x,int y,int z){f[++head]=(yyy){y,z,h[x]};h[x]=head;}
}s;
long long d[200039][2][2];
struct ques{
long long w;int to,i1,i2;
bool operator <(const ques &x)const{return w>x.w;}
}now;
priority_queue<ques>q;
int main(){
//freopen("1.in","r",stdin);
register int i;register yyy tmp;register ques now;
memset(d,0x3f,sizeof(d));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&z),s.add(x,y,z),s.add(y,x,z);
d[1][0][0]=0;q.push((ques){0,1,0,0});
while(!q.empty()){
now=q.top();q.pop();flag[now.to][now.i1][now.i2]=0;
for(beg(now.to);end;go){
tmp=s.f[cur];
if(d[tmp.to][now.i1][now.i2]>d[now.to][now.i1][now.i2]+tmp.w){
d[tmp.to][now.i1][now.i2]=d[now.to][now.i1][now.i2]+tmp.w;
if(!flag[tmp.to][now.i1][now.i2])flag[tmp.to][now.i1][now.i2]=1,q.push((ques){d[tmp.to][now.i1][now.i2],tmp.to,now.i1,now.i2});
}
if(!now.i1&&d[tmp.to][1][now.i2]>d[now.to][0][now.i2]+tmp.w*2){
d[tmp.to][1][now.i2]=d[now.to][0][now.i2]+tmp.w*2;
if(!flag[tmp.to][1][now.i2])flag[tmp.to][1][now.i2]=1,q.push((ques){d[tmp.to][1][now.i2],tmp.to,1,now.i2});
}
if(!now.i2&&d[tmp.to][now.i1][1]>d[now.to][now.i1][0]){
d[tmp.to][now.i1][1]=d[now.to][now.i1][0];
if(!flag[tmp.to][now.i1][1])flag[tmp.to][now.i1][1]=1,q.push((ques){d[tmp.to][now.i1][1],tmp.to,now.i1,1});
}
if(!now.i1&&!now.i2&&d[tmp.to][1][1]>d[now.to][0][0]+tmp.w){
d[tmp.to][1][1]=d[now.to][0][0]+tmp.w;
if(!flag[tmp.to][1][1])flag[tmp.to][1][1]=1,q.push((ques){d[tmp.to][1][1],tmp.to,1,1});
}
}
}
for(i=2;i<=n;i++)printf("%lld ",d[i][1][1]);
}
CF1473F
显然最大权闭合子图,正的从源点连边,负的从这个点连向汇点。用正权减去最小割即可。空间复杂度\(O(n^2)\)
然而这道题不允许我们每一个连边。
观察到\(a_i\)很小,所以可以直接只连每个约数的最近一个节点,因为如果这个节点被选那么一定连着更早的节点被选,起到一个迭代的效果。
这样可以做到空间复杂度\(O(n\sqrt w)\)
code:
#include<cstdio>
#include<queue>
#include<cstring>
#define beg(x) int cur=nows[x]
#define end ~cur
#define go cur=tmp.z
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
using namespace std;
int n,m,k,x,y,z,d[4039],nows[4039],ans[139],a[3039],b[3039],now,tot,st,t,fs[3039];
struct yyy{int to,w,z;}tmp;
struct ljb{
int head,h[4039];yyy f[100039];
inline void add(int x,int y,int z){f[head]=(yyy){y,z,h[x]};h[x]=head++;}
}s;
inline void get(int x,int y,int z){s.add(x,y,z);s.add(y,x,0);}
queue<int> q;
inline int bfs(){
while(!q.empty()) q.pop();
memset(d,0x3f,sizeof(d));memset(nows,0,sizeof(nows));
q.push(st);nows[st]=s.h[st];d[st]=0;
while(!q.empty()){
now=q.front();q.pop();
for(beg(now);end;go){
tmp=s.f[cur];
if(tmp.w&&d[tmp.to]>=1e9){
d[tmp.to]=d[now]+1;nows[tmp.to]=s.h[tmp.to];q.push(tmp.to);
if(tmp.to==t) return 1;
}
}
}
return 0;
}
inline int dfs(int x,int sum){
if(x==t) return sum;
yyy tmp;int k,pus=0;
for(beg(x);end;go){
tmp=s.f[cur];nows[x]=cur;
if(tmp.w&&d[tmp.to]==d[x]+1){
k=dfs(tmp.to,min(tmp.w,sum));
if(!k) d[tmp.to]=1e9;
s.f[cur].w-=k;s.f[cur^1].w+=k;
pus+=k;sum-=k;
}
if(!sum) break;
}
return pus;
}
int main(){
// freopen("1.in","r",stdin);
register int i,j;memset(s.h,-1,sizeof(s.h));
scanf("%d",&n);st=0;t=n+1;
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=1;i<=n;i++){
scanf("%d",&b[i]);
if(b[i]>0)get(st,i,b[i]),tot+=b[i];
else get(i,t,-b[i]);
}
for(i=1;i<=n;i++){
for(j=1;j<=a[i];j++)if(a[i]%j==0&&fs[j]) get(i,fs[j],1e9);
fs[a[i]]=i;
}
while(bfs()) tot-=dfs(st,1e9);
printf("%d\n",max(tot,0));
}
CF1473G
咕咕咕