1. 程式人生 > >20180909徐州網絡賽題解

20180909徐州網絡賽題解

之間 printf query ace orm lowbit n) users out

目錄

  • 20180909徐州網絡賽題解
    • A. Hard to prepare
      • MEANING
      • SOLUTION
      • CODE
    • B. BE, GE or NE
      • MEANING
      • SOLUTION
      • CODE
    • F. Features Track
      • CODE
    • G. Trace
      • MENING
      • SOLUTION
      • CODE
    • H. Ryuji doesn‘t want to study
      • MEANING
      • CODE
    • I. Characters with Hash
      • CODE
    • J. Maze Designer
      • MEANING
      • SOLUTION
      • CODE

20180909徐州網絡賽題解

A. Hard to prepare

MEANING

n個點的環,每個點在[0,$2^{k-1}$] 之間選一個值。要求相鄰兩點的權值的二進制至少有一位相同。問方案數

SOLUTION

斷環為鏈,類似染色問題遞歸推導,考慮到爆棧,可能要把遞歸改成遞推

CODE

隊友代碼

#include <bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;
long long qpow(long long a,long long b)
{
    long long res=1;
    while(b)
    {
        if(b%2)
            res = res*a%mod;
        a = a*a%mod;
        b = b/2;
    }
    return res;
}
long long n,k;
long long dp[1000005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld %lld",&n,&k);
        long long x;
        x = qpow(2,k);
        dp[1] = x;
        dp[2] = x*(x-1)%mod;
        for(int i=3;i<=n;i++)
        {
            dp[i] = ( dp[i-2]*(x-1)%mod + ( x*qpow((x-1+mod)%mod,i-2)%mod-dp[i-2] +mod )%mod*(x-2)%mod )%mod;
        }
        printf("%lld\n",dp[n]);
    }
    return 0;
}

B. BE, GE or NE

MEANING

兩個人玩一個galgame,一個人想GoodEnding,另一個想BadEnding。兩人輪流選擇劇情分支,劇情分支有三種,一種會使好感度增加,第二種會使好感度減少,第三種會使好感度取反。兩人都很聰明,問遊戲最後結局(只取決於好感度)如何。

SOLUTION

由於範圍很小,考慮dp

CODE

隊友代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const ll maxn = 1000005;
const ll mod = 1000000007;

ll n,m,k,l;
ll dp[1005][205];
ll a[1005][5];

int main() {
    scanf("%lld%lld%lld%lld",&n,&m,&k,&l);
    k+=100;
    l+=100;
    m+=100;
    for (int i=1; i<=n; i++) {
        for (int j=1; j<=3; j++) {
            scanf("%lld",&a[i][j]);
        }
    }
    for (int j=0; j<=200; j++)
        dp[n+1][j]=j;
    for (int i=n; i>=1; i--) {
        for (int j=200; j>=0; j--) {
            if (i%2) {
                dp[i][j]= 0;
                if (a[i][1])
                    dp[i][j]= max(dp[i][j],dp[i+1][min(j+a[i][1],200ll)]);
                if (a[i][2])
                    dp[i][j]= max(dp[i][j],dp[i+1][max(j-a[i][2],0ll)]);
                if (a[i][3])
                    dp[i][j]= max(dp[i][j],dp[i+1][200-j]);
            } else {
                dp[i][j]= 200;
                if (a[i][1])
                    dp[i][j]= min(dp[i][j],dp[i+1][min(j+a[i][1],200ll)]);
                if (a[i][2])
                    dp[i][j]= min(dp[i][j],dp[i+1][max(j-a[i][2],0ll)]);
                if (a[i][3])
                    dp[i][j]= min(dp[i][j],dp[i+1][200-j]);
            }
        }
    }
    ll ans = dp[1][m];
    if (ans>=k)
        printf("Good Ending\n");
    else if (ans<=l)
        printf("Bad Ending\n");
    else
        printf("Normal Ending\n");
    return 0;
}

F. Features Track

CODE

隊友代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const ll maxn = 1000005;
const ll mod = 1000000007;

map<pll,ll> mp[2];

int main() {
    ll t;
    scanf("%lld",&t);
    while(t--) {
        ll n;
        scanf("%lld",&n);
        ll cur = 0;
        mp[0].clear();
        mp[1].clear();
        ll ans = 0;
        for (ll i=1; i<=n; i++) {
            ll pre = cur;
            cur = 1-cur;
            mp[cur].clear();
            ll k ;
            scanf("%lld",&k);
            set<pll> ss;
            for (ll j=1; j<=k; j++) {
                ll x,y;
                scanf("%lld%lld",&x,&y);
                pll cat  =  pll(x,y);
                ll val = 1 + mp[pre][cat];
                ans = max(ans,val);
                mp[cur][cat]=val;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

G. Trace

MENING

技術分享圖片
在平面坐標系xOy的第一象限中,給你一個點,分別向xy軸作垂線可以和坐標軸圍成一個矩形。現在依次給出n個點,後來的矩形會覆蓋前面的,保證一個矩形不會被完全覆蓋,問圖中紅線長度。

SOLUTION

我們可以倒序向圖中加入點。
每當一個點加入時,分別向xy軸作垂線直到碰到紅線時停下,答案就會增加所畫線段的長度。
可以分別對x軸y軸建線段樹,區間修改,單點查詢。註意需要離散化。

CODE

#define FILE_IN() freopen("C:\\Users\\dmt\\Desktop\\in.txt","r",stdin);
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 50005;
struct sgt {
    struct SegmentTree {
        int l,r;
        ll sum,add;
        #define l(x) tree[x].l
        #define r(x) tree[x].r
        #define sum(x) tree[x].sum
        #define add(x) tree[x].add
    } tree[MAXN<<2];
    int a[MAXN],n;
    void build(int p,int l,int r) {
        l(p) = l,r(p) = r;
        if(l==r) {
            sum(p) = a[l];
            return;
        }
        int mid = (l+r)/2;
        build(p*2,l,mid);
        build(p*2+1,mid+1,r);
        sum(p) = sum(p*2) + sum(p*2+1);
    }
    void spread(int p) {
        if(add(p)) {
            sum(p*2)+=add(p)*(r(p*2)-l(p*2)+1);
            sum(p*2+1)+=add(p)*(r(p*2+1)-l(p*2+1)+1);
            add(p*2)+=add(p);
            add(p*2+1) += add(p);
            add(p) = 0;
        }
    }
    void change(int p,int l,int r,int d) {
        if(l<=l(p)&&r>=r(p)) {
            sum(p)+=(ll)d*(r(p)-l(p)+1);
            add(p)+=d;
            return;
        }
        spread(p);
        int mid = (l(p)+r(p))/2;
        if(l<=mid)change(p*2,l,r,d);
        if(r>mid) change(p*2+1,l,r,d);
        sum(p) = sum(p*2)+sum(p*2+1);
    }
    ll ask(int p,int l,int r) {
        if(l<=l(p)&&r>=r(p))return sum(p);
        spread(p);
        int mid = (l(p)+r(p))/2;
        ll val = 0;
        if(l<=mid)val+=ask(p*2,l,r);
        if(r>mid)val+=ask(p*2+1,l,r);
        return val;
    }
} axis_x,axis_y;

struct data{
    int x,y,ind;
    int lx,ly;
}point[MAXN];

int lisan_x[MAXN],lisan_y[MAXN];

bool cmpx(data a,data b){
    if(a.x!=b.x)return a.x<b.x;
    return a.ind<b.ind;
}

bool cmpy(data a,data b){
    if(a.y!=b.y)return a.y<b.y;
    return a.ind<b.ind;
}

bool cmp(data a,data b){
    return a.ind<b.ind;
}

int main() {
//    FILE_IN();
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&point[i].x,&point[i].y);
        point[i].ind = i;
    }
    //離散化
    sort(point+1,point+n+1,cmpx);
    for(int i=1;i<=n;i++){
        lisan_x[i] = point[i].ind;
        point[i].lx  = i;
    }
    sort(point+1,point+n+1,cmpy);
    for(int i=1;i<=n;i++){
        lisan_y[i] = point[i].ind;
        point[i].ly  = i;
    }
    sort(point+1,point+n+1,cmp);
    for(int i=1;i<=n;i++){
        axis_x.a[i] = axis_y.a[i] = 0;
    }
    //建線段樹
    axis_x.build(1,1,n);
    axis_y.build(1,1,n);
    ll ans = 0;
    for(int i = n;i>=1;i--){
        ll lx = point[i].lx;
        ll ly = point[i].ly;
        ll x = point[i].x;
        ll y = point[i].y;
        ll downy = axis_x.ask(1,lx,lx);
        ll downx = axis_y.ask(1,ly,ly);
        ans += x-point[lisan_x[downx]].x;
        ans += y-point[lisan_y[downy]].y;
        axis_x.change(1,downx,lx,ly-downy);
        axis_y.change(1,downy,ly,lx-downx);
    }
    cout<<ans<<endl;
    return 0;
}

H. Ryuji doesn‘t want to study

MEANING

給一個長度為n的數組a[n],q次詢問,每次詢問給出一個長度為L的區間[l,r],回答
a[l]×L+a[l+1]×(L?1)+?+a[r?1]×2+a[r]

CODE

隊友代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const ll maxn = 1000005;
const ll mod = 1000000007;

ll n,q;
struct ST {
    ll c[maxn];
    ll lowbit(ll x) {
        return -x&x;
    }
    void update(ll x,ll v) {
        while(x<=n) {
            c[x]+=v;
            x+=lowbit(x);
        }
    }
    ll query(ll x) {
        ll ret = 0;
        while(x>0) {
            ret+=c[x];
            x-=lowbit(x);
        }
        return ret;
    }
    ll query(ll l,ll r) {
        return query(r)-query(l-1);
    }

} s1,s2;

ll a[maxn];

int main() {
    scanf("%lld%lld",&n,&q);
    for (int i=1; i<=n; i++) {
        scanf("%lld",&a[i]);
        s1.update(i,a[i]*(n-i+1));
        s2.update(i,a[i]);
    }
    for (ll qq =1; qq<=q; qq++) {
        ll op;
        scanf("%lld",&op);
        if (op==1) {
            ll l,r;
            scanf("%lld%lld",&l,&r);
            ll ans = s1.query(l,r) - s2.query(l,r)*(n-r);
            printf("%lld\n",ans);
        } else {
            ll x,y;
            scanf("%lld%lld",&x,&y);
            s2.update(x,y-a[x]);
            s1.update(x,(y-a[x])*(n-x+1));
            a[x]=y;
        }
    }
    return 0;
}

I. Characters with Hash

簽到題

CODE

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const ll maxn = 1000005;
const ll mod = 1000000007;

char str[maxn];
int cnt = 0;

int main() {
    ios::sync_with_stdio(false);
    cin.tie();
    int t;
    cin>>t;
    while(t--) {
        int n;
        char ch;
        cin>>n;
        cin>>ch;
        cin>>str;
        cnt = 0;
        for (int i=0; i<n; i++) {
            int tmp = abs(ch-str[i]);
            if (tmp==0)
                cnt+=2;
            else if (tmp<10) {
                cnt++;
                break;
            } else
                break;
        }
        int ans = n*2-cnt;
        if (ans==0)
            ans=1;
        cout<<ans<<endl;
    }
    return 0;
}

J. Maze Designer

MEANING

給一個n*m的網格圖,給出每個格子與它相鄰格子之間建堵墻的花費,要你找到一種建墻方案,使得在滿足圖中任意兩個格子只有一條路徑的前提下,總花費最小。然後就該方案給出q次詢問,每次詢問給定的兩點之間的距離。

SOLUTION

題目要求圖中任意兩個格子只有一條路徑,實際上就是一棵樹。既然建墻(拆邊)的總花費要最小,那麽建邊的總花費就是最大。所以跑一邊Kruskal,求出最大生成樹,時間復雜度O(nmlog(nm))。在樹上詢問兩點之間的距離可以通過求出最近公共祖先,兩點之間的距離就是dist(x,y) = deep(x)+deep(y)-2*deep(LCA(x,y)),時間復雜度O(qlog(nm))。

CODE

#define FILE_IN() freopen("C:\\Users\\dmt\\Desktop\\in.txt","r",stdin);
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 250005;
const int MAXE = 500005;
int n,m,t;

struct rec{
    int x,y,z;
}mapp[500010];
int cnt;
bool cmp(rec a,rec b){
    return a.z>b.z;
}

struct edge{
    int u,v,w,nex;
}ed[MAXE];

int head[MAXN],tot;

void addedge(int u,int v,int w){
    tot++;
    ed[tot].u = u;
    ed[tot].v = v;
    ed[tot].w = w;
    ed[tot].nex = head[u];
    head[u] = tot;
}

int fa[MAXN];

int DjsGet(int x){
    if(x==fa[x])return x;
    return fa[x] = DjsGet(fa[x]);
}

int deep[MAXN],anc[MAXN][20];

queue<int> q;

void bfs() {
    q.push(1);
    deep[1] = 1;
    while(q.size()) {
        int x = q.front();
        q.pop();
        for(int i=head[x]; i; i=ed[i].nex) {
            int y = ed[i].v;
            if(deep[y])continue;
            deep[y] = deep[x]+1;
            anc[y][0] = x;
            for(int j=1;j<t;j++){
                anc[y][j] = anc[anc[y][j-1]][j-1];
            }
            q.push(y);
        }
    }
}

int lca(int x,int y) {
    if(deep[x]<deep[y])swap(x,y);
    for(int i=t-1; i>=0; i--)  //to same deep;
        if(deep[y]<=deep[anc[x][i]])
            x = anc[x][i];
    if(x==y)return x;
    for(int i=t-1; i>=0; i--)
        if(anc[x][i]!=anc[y][i]) {
            x = anc[x][i];
            y = anc[y][i];
        }
    return anc[x][0];
}

int main() {
//    FILE_IN();
    scanf("%d%d",&n,&m);
    t = (int)log(n*m)/log(2)+1;
    getchar();
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            int u = i*m+j+1;
            char D,R;
            D = getchar();
            int w;
            scanf("%d",&w);
            getchar();
            if(D=='D'){
                int v = (i+1)*m+j+1;;
                mapp[++cnt] = {u,v,w};
            }
            R = getchar();
            scanf("%d",&w);
            getchar();
            if(R=='R'){
                int v = i*m+j+2;
                mapp[++cnt] = {u,v,w};
            }
        }
    }
    sort(mapp+1,mapp+cnt+1,cmp);
    for(int i = 1;i<=n*m;i++)fa[i] = i;
    for(int i=1;i<=cnt;i++){
        int x = DjsGet(mapp[i].x);
        int y = DjsGet(mapp[i].y);
        if(x==y)continue;
        fa[x] = y;
        addedge(mapp[i].x,mapp[i].y,mapp[i].z);
        addedge(mapp[i].y,mapp[i].x,mapp[i].z);
    }
    bfs();
    int q;
    scanf("%d",&q);
    while(q--){
        int x_1,y_1,x_2,y_2;
        scanf("%d%d%d%d",&x_1,&y_1,&x_2,&y_2);
        int u = (x_1-1)*m+y_1;
        int v = (x_2-1)*m+y_2;
        int la = lca(u,v);
        printf("%d\n",deep[u]+deep[v]-2*deep[la]);
    }
    return 0;
}

20180909徐州網絡賽題解