【Codeforces】 Educational Round 54 Div. 2 A-G
傳送門: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
將每個結點轉成平面上的一個點的深度看做
座標,
序為
座標,每次操作相當於一個矩陣區域的加值。最終查詢矩陣每個點的值。
離線下來線段樹維護即可。
#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
兩次貪心取。
一次貪心
後跟
個
。判每次剩下的
的個數。
一次貪心
後跟
個
。判每次剩下的
的個數。
若兩次都合法,就有解。
#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
考慮單組詢問的做法,設 為當前在 處,且 時的狀態, 表示必勝, 表示必敗。
顯然答案與 的具體值無關,只與 的奇偶性有關, 的第二維 可以省略,只需要記錄每個點 的值。
則
- 後 個位置中有一個位置 滿足 ,則當前狀態必勝。
- 後繼狀態全為必勝,則只有 為偶數( 為奇數)時,能夠達到必勝狀態。
於是從後往前 ,得到了一個 的做法。
區間操作顯然要上顆線段樹,發現只需要記錄一個關鍵資訊“後繼狀態中最近的必敗狀態和當前位置之間的距離
”,於是考慮對於每個結點構造一個函式
,分別表示初始狀態
為
時,倒序
轉移完該結點管轄區間後的狀態的
。
這樣每次就可以
合併了。
考慮對於單個點的初始化:
(情況1.)
設
表示後繼狀態全為必勝的狀態。
為奇數時,
為偶數時,
對於區間加值的操作:偶數之間忽略,奇數則區間取反。所以需要每個結點維護區間全部值取反後的 函式,區間加操作轉換成了區間 ,打個 後標記永久化即可。
#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;
}