Codeforces Global Round1 題解

A

如果bb爲偶數,那麼只需關心aa的最後一位的奇偶性即可。

如果bb爲奇數,那麼顯然aai=1kai\sum_{i=1}^ka_i奇偶性相同。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd(){
    int a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
ll rdll(){
    ll a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}

const int N=100005;

int b,n,a[N],s;

int main(){
	scanf("%d%d",&b,&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	if(b&1)for(int i=1;i<=n;i++)s=(s^a[i])&1;
	else s=a[n]&1;
	if(s)printf("odd");else printf("even");
	return 0;
}

B

如果只能使用kk次膠帶,顯然在nn個點的n1n-1個間隔中取nkn-k個連接。

貪心,直接取間隔長度最小的即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd(){
    int a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
ll rdll(){
    ll a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}

const int N=100005;

int n,m,k,a[N],b[N];
ll s;
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)scanf("%d",&b[i]);k=n-k;
	for(int i=1;i< n;i++)a[i]=b[i+1]-b[i]-1;sort(a+1,a+n);
	for(int i=1;i<=k;i++)s+=a[i];
	printf("%I64d",s+n);
	return 0;
}

C

看到公式,亂糟糟的,毫無頭緒?先打表找規律試試。

發現一個規律:

對於aa,設x=maxx s.t. 2x1ax=\max x\text{ s.t. }2^x-1\le a,則如果a2x1a\ne2^x-1那麼f(a)=2x1f(a)=2^x-1

如果a=2x1a=2^x-1怎麼辦?看起來沒規律?直接打表。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd(){
    int a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
ll rdll(){
    ll a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}

const int N=100005;

int n,t;

int main(){
	scanf("%d",&t);
	while(t--){
	    scanf("%d",&n);
        if(n==1)printf("0\n");
        else if(n==3)printf("1\n");
        else if(n==7)printf("1\n");
        else if(n==15)printf("5\n");
        else if(n==31)printf("1\n");
        else if(n==63)printf("21\n");
        else if(n==127)printf("1\n");
        else if(n==255)printf("85\n");
        else if(n==511)printf("73\n");
        else if(n==1023)printf("341\n");
        else if(n==2047)printf("89\n");
        else if(n==4095)printf("1365\n");
        else if(n==8191)printf("1\n");
        else if(n==16383)printf("5461\n");
        else if(n==32767)printf("4681\n");
        else if(n==65535)printf("21845\n");
        else if(n==131071)printf("1\n");
        else if(n==262143)printf("87381\n");
        else if(n==524287)printf("1\n");
        else if(n==1048575)printf("349525\n");
        else if(n==2097151)printf("299593\n");
        else if(n==4194303)printf("1398101\n");
        else if(n==8388607)printf("178481\n");
        else if(n==16777215)printf("5592405\n");
        else if(n==33554431)printf("1082401\n");
	    else{
	        int a=1;
	        while(a<n)a=a<<1|1;
	        printf("%d\n",a);
	    }
	}
	return 0;
}

D

第一眼感覺貪心不可做?然後發現一個顯然的性質:

存在一個最優解,使對於任意ii[i,i+1,i+2][i,i+1,i+2]最多出現22次。

接下來就可以無腦DP了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd(){
    int a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
ll rdll(){
    ll a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
void chkmax(ll &a,ll b){if(a<b)a=b;}

const int N=1000005;

int n,m,a[N];
ll d[N][3][3],v[N][3][3],s;

int main(){
	m=rd(),n=rd();while(m--)++a[rd()];
	v[0][0][0]=1;
	for(int i=1;i<=n;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++)for(int l=0;l<3;l++){
	    if(!v[i-1][j][k])continue;
	    if(i>n-2&&l)continue;
		if(j+k+l<=a[i]){
			chkmax(d[i][k][l],d[i-1][j][k]+(a[i]-j-k-l)/3+l);
			v[i][k][l]=1;
		}
	}
	printf("%I64d",d[n][0][0]);
	return 0;
}

E

一個重要結論:對於一次在序列AA上的操作,AA的差分序列AA&#x27;恰好交換了相鄰的2項。

所以檢查首尾和排序後的差分序列即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd(){
    int a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
ll rdll(){
    ll a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}

const int N=100005;

int n,a[N],b[N];

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%d",&b[i]);
	if(a[1]!=b[1]||a[n]!=b[n]){printf("No");return 0;}
	for(int i=1;i<n;i++)a[i]=a[i+1]-a[i],b[i]=b[i+1]-b[i];
	sort(a+1,a+n),sort(b+1,b+n);
	for(int i=1;i<n;i++)if(a[i]!=b[i]){printf("No");return 0;}
	printf("Yes");
	return 0;
}

F

不難發現,每次把當前節點uu移動到它的某個兒子vv時,

vv子樹內的葉子節點到當前節點距離減少w(u,v)w(u,v),其他葉子節點到當前節點距離增加w(u,v)w(u,v)

由於圖的節點按DFS序編號,所以一個點子樹內葉子節點的編號都在某個區間內。

所以更換當前節點可以轉換爲有限次區間加。

至於詢問?離線,當DFS到某個點時回答從這個點出發的詢問,直接轉換爲區間最小值即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd(){
    int a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
ll rdll(){
    ll a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}

const int N=500005;
const ll inf=1000000000000000ll;
int n,q,cnt,st[N],ed[N];
vector<int>e[N],f[N],ql[N],qr[N],qi[N];
ll d[N],tre[N<<2],lazy[N<<2],ans[N],D;
void dfs(int v,int fa,ll dep){
    if(e[v].size())d[v]=inf;else d[v]=dep;
    st[v]=++cnt;
    for(int i=0;i<(int)e[v].size();i++)dfs(e[v][i],v,dep+f[v][i]);
    ed[v]=  cnt;
}
void in();
#define mid ((l+r)>>1)
#define ls o<<1,l,mid
#define rs o<<1|1,mid+1,r
void pu(int o){tre[o]=min(tre[o<<1],tre[o<<1|1]);}
void pt(int o,ll v){tre[o]+=v,lazy[o]+=v;}
void pd(int o){pt(o<<1,lazy[o]),pt(o<<1|1,lazy[o]),lazy[o]=0;}
void build(int o,int l,int r){
    if(l==r){tre[o]=d[l];return;}
    build(ls),build(rs),pu(o);
}
void add(int o,int l,int r,int L,int R,ll v){
    if(r<L||R<l)return;
    if(L<=l&&r<=R){pt(o,v);return;}
    pd(o),add(ls,L,R,v),add(rs,L,R,v),pu(o);
}
ll query(int o,int l,int r,int L,int R){
    if(r<L||R<l)return inf;
    if(L<=l&&r<=R)return tre[o];
    pd(o);return min(query(ls,L,R),query(rs,L,R));
}
void solve(int v,int fa,int la){
    D+=la,add(1,1,n,st[v],ed[v],-la-la);
    for(int i=0;i<(int)qi[v].size();i++)ans[qi[v][i]]=D+query(1,1,n,ql[v][i],qr[v][i]);
    for(int i=0;i<(int)e[v].size();i++)solve(e[v][i],v,f[v][i]);
    D-=la,add(1,1,n,st[v],ed[v], la+la);
}
int main(){
	in();
	dfs(1,0,0);
	build(1,1,n);
	solve(1,0,0);
	for(int i=1;i<=q;i++)printf("%I64d\n",ans[i]);
	return 0;
}
void in(){
	n=rd(),q=rd();
	for(int i=2;i<=n;i++){
	    int x=rd(),y=rd();
	    e[x].push_back(i);
	    f[x].push_back(y);
	}
	for(int i=1;i<=q;i++){
	    int x=rd(),y=rd(),z=rd();
	    ql[x].push_back(y);
	    qr[x].push_back(z);
	    qi[x].push_back(i);
	}
}

G

首先,可以把白點轉換爲無色點:

WtoN

顯然在ABCD中雙方都無法獲勝。如果白子游戲開始先搶佔A,那麼黑子必須搶佔B,而C、D就不重要了。


現在考慮只有無色點的情況。

如果發生以下2種情況,那麼白子獲勝:

有度數4\ge4的點 有度數3\ge3且有2\ge2個非葉子鄰居的點
D4 D3

顯然,如果有3\ge3個度數3\ge3的點,那麼白子同樣獲勝。

那麼其他情況,看似一定打平。但有一個例外:

OddBone

如果“骨頭”的中間部分長度爲奇數(這張圖中長度爲5),那麼白子同樣可以獲勝。

其他情況可以證明是平局。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd(){
    int a=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))a=(a<<1)+(a<<3)+(ch^48),ch=getchar();
    return a;
}
const int N=2000005;
int t,n,m,d[N];
char c[N];
vector<int>e[N];
void add(int v,int u){e[v].push_back(u);e[u].push_back(v);}
void app(int v){e[++n].clear();add(v,n);}
int ac(){
	int v=0;
	for(int i=1;i<=n;i++)if(d[i]>3)return 4;
	for(int i=1;i<=n;i++)if(d[i]>2){
		++v;int x=0;
		for(int j=0;j<d[i];j++)if(d[e[i][j]]!=1)++x;
		if(x>1)return 3;
	}
	if(v>2)return 2;
	return v==2&&(n&1);
}
int main(){
	t=rd();
	while(t--){
	    m=n=rd();
	    for(int i=1;i<=n;i++)e[i].clear();
	    for(int i=1;i<n;i++)add(rd(),rd());
	    scanf("%s",c+1);
	    for(int i=1;i<=m;i++)if(c[i]=='W'){app(i);int v=n;app(v);app(v);}
		for(int i=1;i<=n;i++)d[i]=(int)e[i].size();
		if(ac())puts("White");else puts("Draw");
	}
	return 0;
}

H

咕咕咕。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章