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

版权声明: https://blog.csdn.net/weixin_39792252/article/details/82560736
  •  A. Hard to prepare [计数dp]                                                                                                                    题库链接

        通过率: 76.7 %

        通过人数: 507

题意: 有n个顾客围成一个圆,以及2^{k}顶帽子(编号为0,2,3,...,2^{k} - 1),为每一个顾客戴一顶帽子,要求任意两个相邻的顾客的帽子的编号的同或值为正整数。求帽子的分配方案数。

题解:感谢passer__&&belief01 : DP

计数dp,dp_{[i]}_{[0]}表示第i个位置与第一个位置数字相等的种类数,dp_{[i]}_{[1]}表示第i个位置与第一个位置数字异或为2^{k}的种类数,dp_{i}_{2}表示第i个位置与第一个位置数字相互关系的其他情况,这里先给出状态转移方程:

dp_{[i]}_{[0]} = dp_{[i-1]}_{[0]} + dp_{[i-1]}_{[2]}
dp_{[i]}_{[1]} = dp_{[i-1]}_{[1]} + dp_{[i-1]}_{[2]};
dp_{[i]}_{[2]} = dp_{[i-1]}_{[0]}*(m-2) + dp_{[i-1]}_{[1]}*(m-2) + dp_{[i-1]}_{[2]}*(m-2);

代码:

#include<bits/stdc++.h>
#define ll long long

using namespace std;
const int maxn = 1e6+7;
const int mod = 1e9+7;
ll n, k, dp[maxn][3];


void read(ll &x){
    char ch = getchar();x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}

ll qpow(ll a, ll b) {
    ll ans = 1ll;
    while(b) {
        if(b&1) ans = ans*a%mod;
        a = a*a%mod;
        b>>=1;
    }
    return ans;
}

int main()
{
    ll t; read(t);
    while(t--) {
        read(n);
        read(k);
        ll m = qpow(2ll, k);
        dp[1][0] = m;
        dp[1][1] = dp[1][2] = 0;
        for(int i = 2; i <= n; i++) {
            dp[i][0] = (dp[i-1][0] + dp[i-1][2])%mod;
            dp[i][1] = (dp[i-1][1] + dp[i-1][2])%mod;
            dp[i][2] = (dp[i-1][0]*(m-2)%mod + dp[i-1][1]*(m-2+mod)%mod + dp[i-1][2]*(m-3+mod)%mod)%mod;
        }
        printf("%lld\n", (dp[n][0]+dp[n][2])%mod);
    }
    return 0;
}

        通过率: 66.92 %

        通过人数: 356

 

        通过率: 84.16 %

        通过人数: 170

 

        通过率: 33.67 %

        通过人数: 99

 

       通过率: 61.11 %

       通过人数: 33

 

       通过率: 88.66 %

       通过人数: 1087

题意:给定n张图,每张图有k_{i}个点,求连续出现次数最多的点;

题解:用map记录某个上一次出现的位置和连续出现的次数,然后在更新map时取最大值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<cmath>
#include<string>

using namespace std;
int n;
map<pair<int, int>, int> mp1, mp2;


int main() {
	int t; scanf("%d", &t);
	while(t--) {
		int n; scanf("%d", &n);
		int ans = 0;
		mp1.clear();
		mp2.clear();
		for(int i = 1; i <= n; i++){		
			int k; scanf("%d", &k);
			while(k--){				
				int a, b; scanf("%d%d", &a, &b);
				pair<int, int> p = make_pair(a,b);
				//cout << mp1.count(p) << endl;
				if(mp1.count(p) == 0) {
					mp1[p] = i;
					mp2[p] = 1;
                    ans = max(ans, mp2[p]);
					continue;
				}
				
				if(i == mp1[p]) continue;
				else if(i - mp1[p] == 1) {
					mp1[p] = i;
					mp2[p]++;
					ans = max(ans, mp2[p]);
				} else {
					mp1[p] = i;
					ans = max(ans, mp2[p]);
					mp2[p] = 1;
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

 

  •  G. Trace[树状数组/线段树]                                                                                                                       题库链接

        通过率: 72.86 %

        通过人数: 663

题意:有n次涨潮和退潮,每次的范围是个x * y的矩形,求n次涨退潮后,潮水痕迹的长度。

不存在i,j \in [1,n],i\neq j,x_{i} \leqslant x_{j}\&\&y_{i}\leqslant y_{j} 

题解:从后往前,找到横坐标大于坐标x_{i}的纵坐标的最大值Y,找到纵坐标大于坐标y_{i}的横坐标的最大值X,都减去就是要加的长度,用树状数组/线段树维护即可。

 

/*树状数组*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int maxn = 1e5+7;
int n;
ll x[maxn], y[maxn], mx[maxn*100], my[maxn*100];


int lowbit(int a) {return a&(-a);}
 
void addx(int X, ll k) {
    for(int i = X; i > 0; i -= lowbit(i)) mx[i] = max(mx[i], k);
}
 
void addy(int X, ll k) {
    for(int i = X; i > 0; i -= lowbit(i)) my[i] = max(my[i], k);
}
 
ll queryx(int X) {
    ll sum = 0;
    for(int i = X; i < maxn*100; i += lowbit(i))
        sum = max(mx[i], sum);
    return sum;
}

ll queryy(int X) {
    ll sum = 0;
    for(int i = X; i < maxn*100; i += lowbit(i))
        sum = max(my[i], sum);
    return sum;
}



int main() {
	while(scanf("%d", &n)!=EOF) {
		ll ans = 0;
		memset(mx, 0, sizeof(mx));
		memset(my, 0, sizeof(my));
		for(int i = 0; i < n; i++) scanf("%lld%lld", &x[i], &y[i]);
		for(int i = n-1; i >= 0; i--) {
			ll c = queryx(x[i]);
			ans += y[i] - c;
			c = queryy(y[i]);
			ans += x[i] - c;
			addx(x[i], y[i]);
			addy(y[i], x[i]);
		}
		printf("%lld\n", ans);
	}
	return 0;
}
/*线段树*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
vector<int> sta;
int getid(int x) {
    return lower_bound(sta.begin(),sta.end(),x)-sta.begin()+1;
}
struct SegTree
{
    ll Max[maxn<<2];
    void init() {
        memset(Max,0,sizeof(Max));
    }
    void push_up(int rt) {
        Max[rt] = max(Max[rt<<1],Max[rt<<1|1]);
    }
    void build(int l,int r,int rt) {
        if(l == r) {
            Max[rt] = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        push_up(rt);
    }
    void update(int pos,ll val,int l,int r,int rt) {
        if(l == r) {
            Max[rt] = val;
            return;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) update(pos,val,l,mid,rt<<1);
        else update(pos,val,mid+1,r,rt<<1|1);
        push_up(rt);
    }
    ll query(int ql,int qr,int l,int r,int rt) {
        if(ql == l && qr == r)  return Max[rt];
        int mid = (l + r) >> 1;
        if(qr <= mid) return query(ql,qr,l,mid,rt<<1);
        if(ql > mid) return query(ql,qr,mid+1,r,rt<<1|1);
        return max(query(ql,mid,l,mid,rt<<1),query(mid+1,qr,mid+1,r,rt<<1|1));
    }
}segx,segy;
struct node {
    int x,y;
}querys[maxn];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        segx.init();segy.init();
        
        for(int i=0,x,y;i<n;i++) {
            scanf("%d%d",&x,&y);
            querys[i].x = x;querys[i].y = y;
            sta.push_back(x);sta.push_back(y);
        }
        sort(sta.begin(),sta.end());
        sta.erase(unique(sta.begin(),sta.end()),sta.end());
        int m = sta.size();
        segx.build(1,m,1);segy.build(1,m,1);
        ll res = 0;
        for(int i=n-1;i>=0;i--) {
            int x = getid(querys[i].x),y=getid(querys[i].y);
            ll tmp = segx.query(x,m,1,m,1);
            res += querys[i].y - tmp;
            segx.update(x,querys[i].y,1,m,1);
            tmp = segy.query(y,m,1,m,1);
            res += querys[i].x - tmp;
            segy.update(y,querys[i].x,1,m,1);
        }
        printf("%lld\n",res);
    }
    return 0;
}

 

        通过率: 75.87 %

        通过人数: 1025

 

  •  I. Characters with Hash [easy]                                                                                                                 题库链接

        通过率: 92.93 %

        通过人数: 1485

题意:对于s_{i}就是|seed - s_{i}|,这样转化为两位数,不足两位前面补0,最后拼在一起,求去掉前导0的位数;

题解:直接计算就可以啦,注意全是0,要保留最后一个0;

#include<bits/stdc++.h>
using namespace std;
string str;
inline int check(int x) {
    if(x == 0) return 2;
    int cnt = 0;
    while(x) {
        cnt++;
        x /= 10;
    }
    return cnt;
}
int main()
{
    int caset;cin>>caset;
    while(caset--){
        int n;char c;
        cin>>n>>c;
        cin>>str;
        string ans = "";
        for(int i=0;i<n;i++) {
            int x = abs(str[i]-c);
            if(x == 0) ans += "00";
            else if(x < 10) {
                ans += "0";
                ans += to_string(x);
            }
            else {
                ans += to_string(x);
            }
            //cout<<x<<" "<<ans<<endl;
        }
        //cout<<ans<<endl;
        int len = ans.length();
        int i = 0;
        while(i < len && ans[i] == '0') i++; 
        int res = len - i;
        if(res) printf("%d\n",res);
        else printf("%d\n",1);
    }
    return 0;
}

 

  •  J. Maze Designer []                                                                                                                         题库链接

        通过率: 78.55 %

        通过人数: 227

 

  •  K. Morgana Net                                                                                                                         题库链接

        通过率: 58.64 %

        通过人数: 95

 

展开阅读全文

没有更多推荐了,返回首页