ACM-ICPC 2018 徐州赛区网络预赛 ABCFGHIJ

按过题顺序丢 IGHJFABC

I 好像是个模拟 队友写的
https://nanti.jisuanke.com/t/31461

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll long long
#define fi first
#define se second
#define pb push_back
#define mst(a,b) memset(a,b,sizeof a)
#define mp make_pair
#define x first
#define y second
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
const int maxn = 1e6 + 10;
const int MAXM = 2e6 + 10;
const double eps = 1e-7;
char s1[5],s2[maxn];
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int n;
        scanf("%d",&n);
        scanf("%s",s1);
        scanf("%s",s2);
        bool flag = false;
        int ans = 0;
        for(int i = 0; i < n; i++) {
            int num = abs(s1[0] - s2[i]);
            if(!flag) {
                if(num == 0) continue;
                else {
                    flag = true;
                    if(num < 10) ans = 1;
                    else ans = 2;
                }
            } else ans += 2;
        }
        if(ans == 0) ans = 1;
        printf("%d\n",ans);
    }
    return 0;
}

G
https://nanti.jisuanke.com/t/31459
前面的矩形会被后面的覆盖
所以考虑倒过来做
矩形不互相包含
那么矩形肯定都是相对另一个矩形一个坐标长出一些一个坐标短一些
维护一个坐标轴上已有的前x个坐标的最大值

队友写的

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e4 + 10;
pair<int,int> a[maxn];
int x[maxn],y[maxn];
int bitx[maxn],bity[maxn];
void update(int bit[],int x,int v,int n) {
    while(x<=n) {
        bit[x]=max(bit[x],v);
        x+= x& -x;
    }
}
int query(int bit[],int x) {
    int ret=0;
    while(x) {
        ret=max(ret,bit[x]);
        x-= x&-x;
    }
    return ret;
}
int main() {
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%d%d",&x[i],&y[i]);
        a[i].first=x[i];
        a[i].second=y[i];
    }
    sort(x+1,x+1+n);
    sort(y+1,y+1+n);
    for(int i=1; i<=n; i++) {
        a[i].first=lower_bound(x+1,x+1+n,a[i].first)-x;
        a[i].second=lower_bound(y+1,y+1+n,a[i].second)-y;
    }
    ll ans=0;
    for(int i=n; i; i--) {
        int qq = query(bitx,a[i].first);
        ans+=x[a[i].first]-x[query(bitx,a[i].first)];
        qq = query(bity,a[i].second);
        ans+=y[a[i].second]-y[query(bity,a[i].second)];
        update(bitx,a[i].first,a[i].first,n);
        update(bity,a[i].second,a[i].second,n);
        //cout<<ans<<endl;
    }
    printf("%lld\n",ans);
    return 0;
}

H
https://nanti.jisuanke.com/t/31460
求的是a[i]对a[j]多i-j次贡献的总贡献
直接维护两个线段树
一个是对每个i有n-i+1次的贡献
另一个是1次贡献
那么第一颗查询l,r得到的贡献次数就是n-i+1,n-i,n-i-1……
第二颗查询l,r得到的贡献次数是1,1,1,1……
则显然存在一个k使得第一颗的每个贡献次数-k等于len,len-1,len-2……
也就是第一颗的答案 减去第二颗的答案*k

队友写的

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ll long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
#define mst(a,b) memset(a,b,sizeof a)
#define mp make_pair
#define x first
#define y second
#define lc (o<<1)
#define rc ((o<<1)^1)
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
const int maxn = 1e5 + 10;
const int MAXM = 2e6 + 10;
const double eps = 1e-7;
int n,q;
ll a[maxn],sum[2][maxn<<2];
void pushup(int rt,int id) {
    sum[id][rt] = sum[id][rt<<1] + sum[id][rt<<1|1];
}

void build(int rt,int l,int r,int id) {
    if(l == r) {
        if(id == 0) sum[id][rt] = a[l];
        else sum[id][rt] = a[l] * (ll)(n - l + 1);
        return ;
    }
    int mid = (l + r) >> 1;
    build(rt<<1,l,mid,id);
    build(rt<<1|1,mid+1,r,id);
    pushup(rt,id);
}
void change(int rt,int l,int r,int p,ll v,int id) {
    if(l == r) {
        if(id == 0) sum[id][rt] = a[l];
        else sum[id][rt] = 1ll * a[l] * (n - l + 1);
        return ;
    }
    int mid = (l + r) >> 1;
    if(p <= mid) change(rt<<1,l,mid,p,v,id);
    else change(rt<<1|1,mid+1,r,p,v,id);
    pushup(rt,id);
}
ll query(int rt,int l,int r,int ql,int qr,int id) {
    if(l >= ql && r <= qr) return sum[id][rt];
    int mid = (l + r) >> 1;
    ll ans = 0;
    if(ql <= mid) ans += query(rt<<1,l,mid,ql,qr,id);
    if(qr > mid) ans += query(rt<<1|1,mid+1,r,ql,qr,id);
    return ans;
}

int main() {
#ifdef local
    freopen("in","r",stdin);
//    freopen("aa.txt","w",stdout);
#endif
    scanf("%d%d",&n,&q);
    mst(sum,0);
    for(int i = 1; i <= n; i++)
        scanf("%lld",&a[i]);
    build(1,1,n,0);
    build(1,1,n,1);
    while(q--) {
        int op,l,r;
        scanf("%d%d%d",&op,&l,&r);
        if(op == 1) {
            int len = r - l + 1;
            ll ans = query(1,1,n,l,r,1) - 1ll * (n-l+1-len) * query(1,1,n,l,r,0);
            printf("%lld\n",ans);
        } else {
            a[l] = (ll)r;
            change(1,1,n,l,(ll)r,0);
            change(1,1,n,l,(ll)r,1);
        }
    }
    return 0;
}

J
https://nanti.jisuanke.com/t/31462
n*m的迷宫 让你建一些墙使得每对点之间只有一条路径
那么肯定墙花费越大越不选
那么不选就代表这面墙的位置形成一个通道也就是边
转化成最大生成树问题

然后对一棵树上两点距离查询写一个lca

我写的代码

#include <bits/stdc++.h>
#define sd(a) scanf("%d",&a)
using namespace std;
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
const int maxn = 250000+10;
vector<int>g[maxn];
int fa[maxn];
int faf(int x) {
    return fa[x]==x?x:fa[x] = faf(fa[x]);
}
void un(int a,int b) {
    int f1 = faf(a),f2 = faf(b);
    if(f1!=f2)fa[f2]=f1;
}
int dep[maxn];
int f[maxn][20];
void dfs(int u,int ft) {
    int sz = g[u].size();
    for(int j=1; j<20; ++j) {
        f[u][j] = f[ f[u][j-1] ][ j-1 ];
    }
    for(int j=0; j<sz; ++j) {
        int v = g[u][j];
        if(v==ft)continue;
        f[v][0] = u;
        dep[v] = dep[u]+1;
        dfs(v,u);
    }
}
int lca(int a,int b) {
    if(dep[a]<dep[b])swap(a,b);
    int ans = 0;
    for(int i=19; i>=0; --i) {
        if(dep[f[a][i]]>=dep[b]) {
            ans += 1<<i;
            a = f[a][i];
        }
    }
    if(a==b)return ans;
    for(int i=19; i>=0; --i) {
        if(f[a][i]!=f[b][i]) {
            ans += 2<<i;
            a = f[a][i];
            b = f[b][i];
        }
    }
    ans += 2;
    return ans;
}
int getid(int x,int y,int m) {
    return (x-1)*m+y;
}
struct node {
    int w,u,v;
    node() {}
    node(int a,int b,int c) {
        u = a,v = b,w = c;
    }
    bool operator <(const node &o)const {
        return w<o.w;
    }
};
int main() {
    int n,m;
    sd(n),sd(m);
    int tot = n*m;
    vector< node > v;
    for(int i=1; i<=tot; ++i) {
        char s[10];
        scanf("%s",s);
        int nt = i;
        int x;
        sd(x);
        if(s[0]!='X') {
            if(s[0]=='D')nt = i + m;
            else nt = i + 1;
            v.pb(node(i,nt,-x));
        }
        scanf("%s",s);
        sd(x);
        if(s[0]!='X') {
            if(s[0]=='D')nt = i + m;
            else nt = i+1;
            v.pb(node(i,nt,-x));
        }
        fa[i] = i;
    }
    sort(v.begin(),v.end());
    int sz = v.size();
    dep[1] = 1;
    for(int i=0; i<sz; ++i) {
        int u = v[i].u;
        int t = v[i].v;
        if(faf(u)==faf(t))continue;
        g[u].pb(t);
        g[t].pb(u);
        un(u,t);
    }
    dfs(1,0);
    int q;
    sd(q);
    for(; q--;) {
        int x1,y1,x2,y2;
        sd(x1),sd(y1),sd(x2),sd(y2);
        int x = getid(x1,y1,m),y = getid(x2,y2,m);
        int ans = lca(x,y);
        printf("%d\n",ans);
    }
    return 0;
}

F
https://nanti.jisuanke.com/t/31458

给n个时间点 每个时间点出现了一些位置
求同一位置最长连续出现的时间

记录每个位置出现的时间点 然后遍历

队友写的

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ll long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mst(a,b) memset(a,b,sizeof a)
#define mp make_pair
#define x first
#define y second
#define lc (o<<1)
#define rc ((o<<1)^1)
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
const int maxn = 1e5 + 10;
const int MAXM = 2e6 + 10;
const double eps = 1e-7;
struct node {
    int x,y,id;
}a[maxn];
bool cmp(node b,node c) {
    if(b.x != c.x) return b.x < c.x;
    else if(b.y != c.y) return b.y < c.y;
    return b.id < c.id;
}
int main() {
#ifdef local
    freopen("in","r",stdin);
//    freopen("aa.txt","w",stdout);
#endif
    int t;
    scanf("%d",&t);
    while(t--) {
        int n;
        scanf("%d",&n);
        int tot = 0;
        for(int i = 1; i <= n; i++) {
            int m;
            scanf("%d",&m);
            while(m--) {
                int x,y;
                scanf("%d%d",&x,&y);
                a[tot].x = x, a[tot].y = y, a[tot].id = i;
                tot++;
            }
        }
        sort(a,a+tot,cmp);
        int prex = a[0].x, prey = a[0].y, preid = a[0].id;
        int ans = 1, sum = 1;
        for(int i = 1; i < tot; i++) {
            if(a[i].x == prex && a[i].y == prey) {
                if(a[i].id == preid) continue;
                else if(a[i].id == preid + 1) sum++, preid = a[i].id, ans = max(ans, sum);
                else sum = 1, preid = a[i].id;
            } else {
                prex = a[i].x, prey = a[i].y, preid = a[i].id;
                sum = 1;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

A
https://nanti.jisuanke.com/t/31453
n个人围成一圈
给每个人一个数字使得任意相邻的人数字同或不为0的方案
考虑第一个数为9
首先填满n个数并且2~n不与前一个同或为0的总方案是(2^k-1)^(n-1)
但是n有可能与1同或为0
所以需要减去第n个与第一个0同或为0的方案
也就是确定了第n个为a,a xnor 0 = 0,然后填前n-1个的方案就是(2^k-1)^(n-2)
而填前n-1个也会有相同情况出现
考虑容斥计算

当n为偶数时会出现考虑0303的情况
但是这种情况本身就会考虑第2~n个与前一个在不合法的情况内
所以得加回来

队友写的

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e4 + 10;
const int mod = 1e9 + 7;

ll qpow(int a,int n)
{
    ll ret=1,k=a;
    while(n)
    {
        if(n&1) ret=ret*k%mod;
        n>>=1;k=k*k%mod;
    }
    return ret;
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,k;scanf("%d%d",&n,&k);
        ll ans=0;
        if(n==1)
        {
            ans=1;
        }
        else if(n==2)
        {
            ans=(qpow(2,k)-1+mod)%mod;
        }
        else if(k==1)
        {
            ans=1;
        }
        else
        {
            ll tt=(qpow(2,k)-1+mod)%mod;
            for(int i=0;i<n;i++)
            {
                ll t=qpow(tt,n-i-1);
                if(i&1)
                {
                    ans-=t;
                    if(ans<0) ans+=mod;
                }
                else 
                {
                    ans+=t;
                    if(ans>=mod) ans-=mod;
                }
                //cout<<i<<' '<<t<<' '<<ans<<endl;
            }
            if(n&1);
            else ans=(ans+1)%mod;
        }
        ans=ans*qpow(2,k)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

B
https://nanti.jisuanke.com/t/31454
博弈dp
直接dpij维护第i次选择时为j的最优情况
然后一次递推 贪心取自己想要的最大或最小

我写的

#include <bits/stdc++.h>
#define sd(a) scanf("%d",&a)
using namespace std;
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
const int maxn = 250000+10;
int a[maxn],b[maxn],c[maxn];
int dp[1005][400];
int main() {
#ifdef local
    freopen("in","r",stdin);
#endif
    int n,m,r,l;
    sd(n),sd(m),sd(r),sd(l);
    for(int i=1; i<=n; ++i) {
        sd(a[i]),sd(b[i]),sd(c[i]);
    }
    ++l;
    --r;
    for(int i=-100; i<=100; ++i) {
        int x = 0  ;
        if(i<l)x = -1;
        else if(i>r) x = 1;
        dp[n+1][i+100] = x;
    }
    for(int i=n; i; --i) {
        if(i&1) {
            for(int j=-100; j<=100; ++j) {
                int mx = -2;
                if(a[i])mx = max(mx,dp[i+1][min(100 ,j+a[i]) + 100]);
                if(b[i])mx = max(mx,dp[i+1][max(-100,j-b[i]) + 100]);
                if(c[i])mx = max(mx,dp[i+1][-j + 100]);
                dp[i][j+100] = mx;
            }
        } else {
            for(int j=-100; j<=100; ++j) {
                int mn = 2;
                if(a[i])mn = min(mn,dp[i+1][min(100 ,j+a[i]) + 100]);
                if(b[i])mn = min(mn,dp[i+1][max(-100,j-b[i]) + 100]);
                if(c[i])mn = min(mn,dp[i+1][-j + 100]);
                dp[i][j+100] = mn;
            }
        }
    }
    if(dp[1][m+100]<0)puts("Bad Ending");
    else if(dp[1][m+100]>0)puts("Good Ending");
    else puts("Normal Ending");
    return 0;
}

C
https://nanti.jisuanke.com/t/31455

先枚举这个人知道的部分
对于他不知道的部分再枚举并且计算期望
选最大的期望加入答案

我写的

#include <bits/stdc++.h>
#define sd(a) scanf("%d",&a)
using namespace std;
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#include <iomanip>
const int maxn = 250000+10;
char s[30][30];
int a[33][33];
int num[33][33];
int p[10];
bool vis[10];
int re[30];
int f[30];
long double de[300];
long double ans = 0;
int pcnt = 0;
void check() {
    ++pcnt;
    for(int i=1; i<=8; ++i)de[i] = 0;
    vector<int>v;
    for(int i=1; i<=9; ++i)if(!vis[i])v.pb(i);
    int sz = v.size();
//    int cc = 0;
    do {
//            cout<<++cc<<endl;
        int pp = 0,pos = 0;
        for(int i=1; i<=3; ++i) {
            for(int j=1; j<=3; ++j) {
                if(a[i][j]>=0)num[i][j] = a[i][j];
                else if(a[i][j]==-1)num[i][j] = p[++pos];
                else num[i][j] = v[pp++];
            }
        }
        int id = 0;
        for(int i=1; i<=3; ++i) {
            int cnt = 0;
            for(int j=1; j<=3; ++j) {
                cnt += num[i][j];
            }
            de[++id] += re[cnt];
        }
        for(int j=1; j<=3; ++j) {
            int cnt = 0;
            for(int i=1; i<=3; ++i) {
                cnt += num[i][j];
            }
            de[++id] += re[cnt];
        }
        {
            int cnt = 0;
            for(int i=1; i<=3; ++i) {
                cnt += num[i][i];
            }
            de[++id] += re[cnt];
            cnt = 0;
            for(int i=1; i<=3; ++i) {
                cnt += num[i][4-i];
            }
            de[++id] += re[cnt];
        }
    } while(next_permutation(v.begin(),v.end()));
    for(int i=1; i<=8; ++i) {
        de[i]/=f[sz];
    }
    long double mx = 0;
    for(int i=1; i<=8; ++i)mx = max(mx,de[i]);
    ans += mx;
    return ;
}
void dfs(int u,int n) {
    if(u>n) {
        check();
        return ;
    }
    for(int i=1; i<=9; ++i) {
        if(!vis[i]) {
            vis[i] = 1;
            p[u] = i;
            dfs(u+1,n);
            vis[i] = 0;
        }
    }
}
int main() {
#ifdef local
    freopen("in","r",stdin);
#endif
    f[0] = 1;
    for(int i=1; i<=9; ++i)f[i] = f[i-1]*i;
    re[6] = 10000;
    re[7] = 36;
    re[8] = 720;
    re[9] = 360;
    re[10] = 80;
    re[11] = 252;
    re[12] = 108;
    re[13] = 72;
    re[14] = 54;
    re[15] = 180;
    re[16] = 72;
    re[17] = 180;
    re[18] = 119;
    re[19] = 36;
    re[20] = 360;
    re[21] = 1080;
    re[22] = 144;
    re[23] = 1800;
    re[24] = 3600;
    int t;
    sd(t);
    for(; t--;) {
        memset(vis,0,sizeof vis);
        pcnt = 0;
        ans = 0;
        for(int i=1; i<=3; ++i)scanf("%s",s[i]+1);
        int know = 0;
        int dontknow = 0;
        for(int i=1; i<=3; ++i)
            for(int j=1; j<=3; ++j) {
                if(s[i][j]=='#')a[i][j] = - 2,++dontknow;
                else if(s[i][j]=='*')a[i][j] = -1,++know;
                else a[i][j] = s[i][j] - '0',vis[a[i][j]] = 1;
            }
        dfs(1,know);
        ans /= pcnt;
        cout<<fixed<<setprecision(10)<<ans<<endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值