传送门:cf1076
A. Minimizing the String
贪心删去第一个字典序大于后一个位置的字母的位置。
#include<bits/stdc++.h>
using namespace std;
int n;
char s[200005];
int main(){
int i,j;
scanf("%d%s",&n,s+1);
for(i=1;i<n;++i)
if(s[i]>s[i+1]) break;
for(j=1;j<=n;++j)
if(i!=j) putchar(s[j]);
return 0;
}
B.Divisor Subtraction
特殊性质:
偶数次数 n/2
奇数 (n-n的最小质因数)/2+1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll n,ans;
int p[N],tot;
bool pri[N];
inline void pre()
{
int i,j,res;
for(i=2;i<N;++i){
if(!pri[i]) p[++tot]=i;
for(j=1;j<=tot && (ll)i*p[j]<N;++j){
res=i*p[j];pri[res]=true;
if(i%p[j]==0) break;
}
}
}
void sol(ll n)
{
int i;
if(!(n&1)) ans=n>>1;
else{
for(i=1;i<=tot;++i) if(n%p[i]==0) break;
if(i<=tot){
ans=1+(n-p[i])/2;
}else{
ans=1;
}
}
}
int main(){
int i,j;pre();
scanf("%I64d",&n);
sol(n);
printf("%I64d",ans);
return 0;
}
C.Meme Problem
解个二元一次方程。
#include<bits/stdc++.h>
using namespace std;
#define db double
int t,d;
int main(){
db a,b,c,g,ans;
scanf("%d",&t);
for(;t;--t){
scanf("%d",&d);
a=1.0;b=-(db)d;c=-b;
g=sqrt(b*b-4*c);
ans=(-b+g)/2.0;
if(ans>=0.0 && ans<=(db)d){
printf("Y %.10lf %.10lf\n",ans,d-ans);
}else{
ans=(-b-g)/2.0;
if(ans>=0.0 && ans<=(db)d)
printf("Y %.10lf %.10lf\n",ans,d-ans);
else printf("N\n");
}
}
return 0;
}
D.Edge Deletion
再也不写SPFA了!!!
跑个最短路树再贪心取
By ccosi, contest: Educational Codeforces Round 54 (Rated for Div. 2), problem: (D) Edge Deletion, Accepted, #
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+100;
typedef long long ll;
int n,m,K,f[N],sz[N],ans[N],cot;
int head[N],to[N<<1],nxt[N<<1],w[N<<1],tot;
ll dis[N],inf;
struct P{
int u;ll d;
bool operator<(const P&ky)const{
return ky.d<d;
}
}temp;
struct LE{
int u,v,w;
bool operator<(const LE&ky)const{
if(u!=ky.u) return u<ky.u;
if(v!=ky.v) return v<ky.v;
return w<ky.w;
}
};
map<LE,int>mp;
priority_queue<P>que;
inline void lk(int u,int v,int vv)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;}
inline void spfa()
{
int i,j,x,y;
memset(dis,0x7f,sizeof(ll)*(n+3));
inf=dis[1];dis[1]=0LL;que.push((P){1,0});
for(;que.size();){
temp=que.top();que.pop();x=temp.u;
if(dis[x]!=temp.d) continue;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(dis[j]<=dis[x]+w[i]) continue;
dis[j]=dis[x]+w[i];
que.push((P){j,dis[j]});
}
}
}
int getfa(int x){return x==f[x]?x:(f[x]=getfa(f[x]));}
void ck(int x,int fr)
{
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr) continue;
printf("%d ",w[i]);ck(j,x);
}
}
bool inq[N];
queue<int>Q;
int main(){
int i,j,x,y,z,pr;
scanf("%d%d%d",&n,&m,&K);
for(i=1;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
mp[(LE){x,y,z}]=i;mp[(LE){y,x,z}]=i;
lk(x,y,z);lk(y,x,z);
}
spfa();
Q.push(1);inq[1]=1;
for(;Q.size();){
if(cot==K) break;
x=Q.front();Q.pop();
for(i=head[x];i;i=nxt[i]){
j=to[i];if(dis[j]>=inf || inq[j] || dis[j]!=dis[x]+w[i]) continue;
cot++;
ans[cot]=mp[(LE){x,j,w[i]}];
Q.push(j);inq[j]=1;
if(cot==K) break;
}
}
printf("%d\n",cot);
for(i=1;i<=cot;++i) printf("%d ",ans[i]);
return 0;
}
E.Vasya and a Tree
将每个结点转成平面上的一个点的深度看做
y
y
y坐标,
d
f
s
dfs
dfs序为
x
x
x坐标,每次操作相当于一个矩阵区域的加值。最终查询矩阵每个点的值。
离线下来线段树维护即可。
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
typedef long long ll;
int n,m,dep[N],df[N],ot[N],dfn,cnt;
int head[N],to[N<<1],nxt[N<<1],tot;
ll ss,ans[N],bit[N];
struct P{
int r,c,v;
P(int r_=0,int c_=0,int v_=0):r(r_),c(c_),v(v_){};
bool operator <(const P&ky)const{
return r<ky.r;
}
}q[N<<2],p[N];
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
inline void ad(int x,ll v)
{for(;x<=n;x+=(x&(-x))) bit[x]+=v;}
inline ll ask(int x)
{
ll re=0LL;
for(;x;x-=(x&(-x))) re+=bit[x];
return re;
}
void dfs(int x,int fa)
{
df[x]=++dfn;
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==fa) continue;
dep[j]=dep[x]+1;dfs(j,x);
}
ot[x]=dfn;
}
int main(){
int i,j,x,y,z;
scanf("%d",&n);
for(i=1;i<n;++i){
scanf("%d%d",&x,&y);
lk(x,y);lk(y,x);
}
dep[1]=1;dfs(1,0);
scanf("%d",&m);
for(i=1;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
q[++cnt]=P(dep[x],df[x],z);
if(ot[x]<n){
q[++cnt]=P(dep[x]+y+1,ot[x]+1,z),
q[++cnt]=P(dep[x],ot[x]+1,-z);
}
q[++cnt]=P(dep[x]+y+1,df[x],-z);
}
sort(q+1,q+cnt+1);
for(i=1;i<=n;++i) p[i]=P(dep[i],df[i],i);
sort(p+1,p+n+1);
for(i=j=z=1;z<=n;i=j){
for(;j<=cnt && q[j].r==p[z].c;++j)
ad(q[j].c,q[j].v);
for(;z<=n && p[z].r<=q[i].r;++z)
ans[p[z].v]=ask(p[z].c);
}
for(i=1;i<=n;++i) printf("%I64d ",ans[i]);
return 0;
}
F.Summer Practice Report
两次贪心取。
一次贪心
T
T
T后跟
k
k
k个
F
F
F。判每次剩下的
F
F
F的个数。
一次贪心
F
F
F后跟
k
k
k个
T
T
T。判每次剩下的
T
T
T的个数。
若两次都合法,就有解。
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
typedef long long ll;
int n,K,a[N],b[N];
ll f[N];
int main(){
int i,j,la,ra,lb,rb,x,y,pr=0;
scanf("%d%d",&n,&K);
for(i=1;i<=n;++i) scanf("%d",&a[i]);
for(i=1;i<=n;++i) scanf("%d",&b[i]);
for(i=1;i<=n;++i){
f[i]=max(0LL,f[i-1]+a[i]-(ll)K*b[i]);
if(f[i]>K) {puts("NO");return 0;}
}
for(i=1;i<=n;++i){
f[i]=max(0LL,f[i-1]+b[i]-(ll)K*a[i]);
if(f[i]>K) {puts("NO");return 0;}
}
puts("YES");
}
G.Array Game
考虑单组询问的做法,设 d p [ i ] [ j ] dp[i][j] dp[i][j]为当前在 b i b_i bi处,且 b i = j b_i=j bi=j时的状态, 1 1 1表示必胜, 0 0 0表示必败。
显然答案与 j j j的具体值无关,只与 j j j的奇偶性有关, d p [ i ] [ j ] dp[i][j] dp[i][j]的第二维 j j j可以省略,只需要记录每个点 D P i = d p [ i ] [ b i x o r 1 ] DP_i=dp[i][b_i\ xor \ 1] DPi=dp[i][bi xor 1]的值。
则 D P i = ( b i x o r 1 ) ∣ ( D P i + 1 x o r 1 ) ∣ ( D P i + 2 x o r 1 ) . . . ( D P i + m x o r 1 ) DP_i=(b_i\ xor 1)|(DP_{i+1}\ xor \ 1)|(DP_{i+2}\ xor \ 1)...(DP_{i+m}\ xor\ 1) DPi=(bi xor1)∣(DPi+1 xor 1)∣(DPi+2 xor 1)...(DPi+m xor 1)
- 后 m m m个位置中有一个位置 j j j满足 d p [ j ] [ b j − 1 ] = 0 dp[j][b_j-1]=0 dp[j][bj−1]=0,则当前状态必胜。
- 后继状态全为必胜,则只有 b i b_i bi为偶数( b i x o r 1 b_i\ xor \ 1 bi xor 1为奇数)时,能够达到必胜状态。
于是从后往前 d p dp dp,得到了一个 O ( n m ) O(nm) O(nm)的做法。
区间操作显然要上颗线段树,发现只需要记录一个关键信息“后继状态中最近的必败状态和当前位置之间的距离
d
i
s
dis
dis”,于是考虑对于每个结点构造一个函数
g
[
i
]
g[i]
g[i],分别表示初始状态
d
i
s
dis
dis为
i
i
i时,倒序
d
p
dp
dp转移完该结点管辖区间后的状态的
d
i
s
dis
dis。
这样每次就可以
O
(
m
)
O(m)
O(m)合并了。
考虑对于单个点的初始化:
g
[
i
]
=
i
+
1
(
1
≤
i
≤
m
)
g[i]=i+1(1\leq i\leq m)
g[i]=i+1(1≤i≤m)(情况1.)
设
g
[
m
+
1
]
g[m+1]
g[m+1]表示后继状态全为必胜的状态。
b
i
b_i
bi为奇数时,
g
[
m
+
1
]
=
0
g[m+1]=0
g[m+1]=0
b
i
b_i
bi为偶数时,
g
[
m
+
1
]
=
1
g[m+1]=1
g[m+1]=1
对于区间加值的操作:偶数之间忽略,奇数则区间取反。所以需要每个结点维护区间全部值取反后的 g ′ g' g′函数,区间加操作转换成了区间 s w a p ( g , g ′ ) swap(g,g') swap(g,g′),打个 l a z y t a g lazytag lazytag后标记永久化即可。
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define lc k<<1
#define rc k<<1|1
using namespace std;
const int N=2e5+20;
typedef long long ll;
int n,m,q,rv[N<<2];ll a[N];
struct node{
int g[2][6];
inline void itia(int op){
for(int i=0;i<m;++i) g[0][i]=g[1][i]=i+1;
g[0][m]=m;g[1][m]=0;
if(op) g[0][m]=0,g[1][m]=m;
}
inline void flp()
{for(int i=0;i<=m;++i) swap(g[0][i],g[1][i]);}
}t[N<<2],temp;
inline node mg(node a,node b)
{
node re;int i,j;
for(i=0;i<2;++i)
for(j=0;j<=m;++j)
re.g[i][j]=a.g[i][b.g[i][j]];
return re;
}
inline void build(int k,int l,int r)
{
if(l==r) {t[k].itia((int)(a[l]&1));return;}
build(lc,l,mid);build(rc,mid+1,r);
t[k]=mg(t[lc],t[rc]);
}
inline void cg(int k,int l,int r,int L,int R)
{
if(L<=l && r<=R) {rv[k]^=1;t[k].flp();return;}
if(L<=mid) cg(lc,l,mid,L,R);
if(R>mid) cg(rc,mid+1,r,L,R);
t[k]=mg(t[lc],t[rc]);
if(rv[k]) t[k].flp();
}
inline node ask(int k,int l,int r,int L,int R)
{
if(L<=l && r<=R) return t[k];
node re;
if(R<=mid) re=ask(lc,l,mid,L,R);
else if(L>mid) re=ask(rc,mid+1,r,L,R);
else re=mg(ask(lc,l,mid,L,R),ask(rc,mid+1,r,L,R));
if(rv[k]) re.flp();
return re;
}
int main(){
int i,j,op,l,r;ll z;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=n;++i) scanf("%I64d",&a[i]);
build(1,1,n);
for(;q;--q){
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%I64d",&z);
if(z & 1) cg(1,1,n,l,r);
}else puts(ask(1,1,n,l,r).g[0][m]?"1":"2");
}
return 0;
}