2017ACM-ICPC广西邀请赛-重现赛

这是在厚林工作室4个人打的一场

骚呢

两年没回去了

这里写图片描述

拿lzy的号打,打的被老刘查水表了

这里写图片描述

01

枚举 k k k^k kk k ≤ 15 k \leq 15 k15
看到我的 T T T就知道我是怎么wa的了。。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll powder(ll a,ll n){
    if(n==0) return 1ll;
    ll ret = powder(a,n/2);
    ret = ret * ret;
    if(n&1) return ret*a;
    return ret;
}

int main(){
    int T;
    ll n;
    while(cin>>n){
        int cnt = 0;
        for(ll i=1;i<=15;i++){
            if(powder(i,i)<=n)
                cnt++;
        }
        cout<<cnt<<endl;
    }
    return 0;
}

#02 Color it

线段树,按y排,存x坐标,维护min

按x排存y坐标也行的,

防止炸空间,可以离散化或者像我这样,用到哪建到哪,最多是nlogn的

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 7;

bool getCol;

struct segTree{
    #define val(x) tree[x].val
    #define lson tree[rt].lc, l, m
    #define rson tree[rt].rc, m+1, r
    static const int TREE_N = N * 3 + 3e5;
    struct node{
        int lc, rc, val;
    } tree[TREE_N];
    int tot, root[55];
    
    void build(){
        memset(tree, 0, sizeof(tree));
        memset(root, 0, sizeof(root));
          tot = 0;
    }
    
    //p: pos, v: val
    void add(int p, int v, int &rt, int l, int r){
        if (!rt) val(rt = ++tot) = v;
        val(rt) = min(val(rt), v);
        if (l == r) return;
        int m = (l + r) >> 1;
        if (p <= m) add(p, v, lson);
        else add(p, v, rson);
    }
    
    void query(int L, int R, int v, int rt, int l, int r){
        if(getCol || !rt) return;
        if(L <= l && r <= R){
            if(val(rt) <= v) getCol = 1; return;
        }
        int m = (l + r) >> 1;
        if (L <= m) query(L, R, v, lson);
        if (R >  m) query(L, R, v, rson);
    }
    #undef val(x)
    #undef lson
    #undef rson
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int op, x, y, c, L, R, X;
      T.build();
    for (; scanf("%d", &op) && op != 3;){
        if (op == 0) T.build();
        else if(op == 1){
            scanf("%d%d%d", &x, &y, &c);
              T.add(y, x, T.root[c], 1, N);
        }else if(op == 2){
            scanf("%d%d%d", &X, &L, &R);
              int ans = 0;
              for(int i = 0; i <= 50; i++){
                getCol = 0;
                T.query(L, R, X, T.root[i], 1, N);
                if (getCol) ans++;
              }
              printf("%d\n",ans);
        }
    }
    return 0;
}

03

统计有多少 V = ( A , B , C , D ) V=(A,B,C,D) V=(A,B,C,D) E = ( A B , B C , C D , D A , A C ) E=(AB,BC,CD,DA,AC) E=(AB,BC,CD,DA,AC)
考虑一个边作为对角线时,如果有K个点跟这个边的两个端点都相连,那么有 C K 2 \textrm{C}_{K}^{2} CK2中方案。
统计时,让条边记录在度数比较少的点处,减少枚举次数,每次将3个边一起算贡献。

#include <bits/stdc++.h>

#define mp make_pair

using namespace std;
typedef long long ll;

const int maxn = 100005;

vector<pair<int,int> > e[maxn];

int du[maxn],u,v,n,m;
ll cnt[maxn<<2];
struct node{
    int u,v;
}info[maxn<<2];

struct Node{
    int idi,idep;
    Node(){}
    Node(int _idi,int _idep){
        idi=_idi;
        idep=_idep;
    }
}a[maxn<<2];

int main(){    
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++)
            e[i].clear();
        memset(a,0,sizeof a);
        memset(du,0,sizeof du);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            du[u]++;du[v]++;
            info[i].u=u;
            info[i].v=v;
        }
        for(int i=1;i<=m;i++){
            u=info[i].u;v=info[i].v;
            if(du[u] < du[v] || (du[u] == du[v] && u < v))
                e[u].push_back(mp(v,i));
            else e[v].push_back(mp(u,i));
        }
        memset(cnt,0,sizeof cnt);
        for(int i=1;i<=m;i++){
            u=info[i].u;v=info[i].v;
            for(auto ep:e[u]) a[ep.first]=Node(i,ep.second);
            for(auto ep:e[v]){
                if(a[ep.first].idi==i){
                    cnt[i]++;
                    cnt[ep.second]++;
                    cnt[a[ep.first].idep]++;
                }
            }
        }
        ll res = 0;
        for(int i=1;i<=m;i++)
            res += (cnt[i]-1ll)*cnt[i]/2ll;
        printf("%lld\n",res);
    }
    return 0;
} 

04

Number of domino tilings of 4 X (n-1) board. 

a n = a n − 1 + 5 a n − 2 + a n − 3 − a n − 4 a_n = a_{n-1} + 5a{n-2} + a_{n-3} - a_{n-4} an=an1+5an2+an3an4,直接用杜教板子。。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head

int _;
ll n;
namespace linear_seq {
    const int N=10010;
    ll res[N],base[N],_c[N],_md[N];

    vector<ll> Md;
    void mul(ll *a,ll *b,ll k) {
        rep(i,0,k+k) _c[i]=0;
        rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
        for (int i=k+k-1;i>=k;i--) if (_c[i])
            rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
        rep(i,0,k) a[i]=_c[i];
    }
    int solve(ll n,VI a,VI b) { 
        ll ans=0,pnt=0;
        ll k=SZ(a);
        assert(SZ(a)==SZ(b));
        rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
        Md.clear();
        rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
        rep(i,0,k) res[i]=base[i]=0;
        res[0]=1;
        while ((1ll<<pnt)<=n) pnt++;
        for (int p=pnt;p>=0;p--) {
            mul(res,res,k);
            if ((n>>p)&1) {
                for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
                rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
            }
        }
        rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
        if (ans<0) ans+=mod;
        return ans;
    }
    VI BM(VI s) {
        VI C(1,1),B(1,1);
        int L=0,m=1,b=1;
        rep(n,0,SZ(s)) {
            ll d=0;
            rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
            if (d==0) ++m;
            else if (2*L<=n) {
                VI T=C;
                ll c=mod-d*powmod(b,mod-2)%mod;
                while (SZ(C)<SZ(B)+m) C.pb(0);
                rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                L=n+1-L; B=T; b=d; m=1;
            } else {
                ll c=mod-d*powmod(b,mod-2)%mod;
                while (SZ(C)<SZ(B)+m) C.pb(0);
                rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                ++m;
            }
        }
        return C;
    }
    int gao(VI a,ll n) {
        VI c=BM(a);
        c.erase(c.begin());
        rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
        return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
    }
};

int main() {
    while(~scanf("%lld",&n)){
        printf("%d\n",linear_seq::gao(VI{1,1, 5, 11, 36, 95, 281, 781, 2245, 6336, 18061, 51205, 145601, 413351, 1174500, 3335651, 9475901, 26915305, 76455961, 217172736},n));
    }
}

05

求三种sum丢掉第k位

预处理出所有的前缀和后缀

黑康说:按位枚举???

#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1e5 + 7;
int arr[N];
int prXor[N], prAnd[N], preOr[N];
int suXor[N], suAnd[N], sufOr[N];

int main(){
    //freopen("in.txt", "r", stdin);
    int n, q;
    for (; ~scanf("%d%d", &n, &q);){
        prXor[0] = suXor[n+1] = 0;
        prAnd[0] = suAnd[n+1] = ~0;
        preOr[0] = sufOr[n+1] = 0;
        
        //printf("%d\n", prAnd[0]);
         
        for (int i = 1; i <= n; i++){
            scanf("%d", &arr[i]);
            prXor[i] = prXor[i-1] ^ arr[i];
            prAnd[i] = prAnd[i-1] & arr[i];
            preOr[i] = preOr[i-1] | arr[i];
        }
        for (int i = n; i >= 1; i--){
            suXor[i] = suXor[i+1] ^ arr[i];
            suAnd[i] = suAnd[i+1] & arr[i];
            sufOr[i] = sufOr[i+1] | arr[i];
        }
        for (int k; q--;){
            scanf("%d", &k);
            int ansXor = prXor[k-1] ^ suXor[k+1];
            int ansAnd = prAnd[k-1] & suAnd[k+1];
            int ansOrr = preOr[k-1] | sufOr[k+1];
            printf("%d %d %d\n", ansAnd, ansOrr, ansXor);
        }
    }    
    return 0;
}

06

好像是个傻逼题,然后犯了傻逼错误

贡献了-6的罚时,

国王的坐标给的那么恶心的数字,就是告诉你,国王不会在wall上,然后要让国王能到达任意地方,就要让这些wall无法形成环就可以了,所以,不是环,树嘛,要求删去的最少,求个最大生成树,然后 a n s = s u m a l l − s u m t r e e ans = sum_{all} - sum_{tree} ans=sumallsumtree

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
using namespace std;
typedef pair<int, int> P;
const int N = 1e5 + 7;

struct Edge{
    int from,to,w;
    Edge(){}
    Edge(int x,int y,int z):from(x),to(y),w(z){}
    bool operator < (const Edge& a) const{return w > a.w;}
} edges[N * 2];

int f[N];
int F(int x){return f[x]==x ? x : (f[x]=F(f[x]));}

bool vis[N];
P kruskal(int n, int m){
    int treenum = n; //forests    
    for (int i = 1;i <= n; i++) f[i] = i;
    sort(edges, edges + m);
    int cnt = 0, ans = 0;
    for (int i = 0; i < m; i++){
        Edge &e = edges[i];
        if (F(e.from) == F(e.to)) continue;
        f[F(e.from)] = F(e.to);
        treenum--;
        ans += e.w;
    }
    return P(treenum, ans);
}

int main(){
    //freopen("in.txt", "r", stdin);
    int n, x, y, u, v, c, m;
    for (; scanf("%d%d", &n, &m)==2;){
        for (int i = 1; i <= n; i++) scanf("%d%d", &x, &y);
        int all = 0;
        for (int i = 0; i < m; i++){
            scanf("%d%d%d", &u, &v, &c);
            edges[i] = Edge(u, v, c);
            all += c;
        }
        P p = kruskal(n, m);
        printf("%d %d\n", m-(n-p.fi), all - p.se);
    }
    return 0;
}

07毛对子和毛顺子

贪心:取i,i-1,i-2这个顺子的时候先把i-1,i-2的对子取掉,取完再取i的对子

#include <bits/stdc++.h>

using namespace std;

int a[1000005],x,n;

int main(){
    while(~scanf("%d",&n)){
        memset(a,0,sizeof a);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            a[x]++;
        }
        int cnt = 0;
        for(int i=1;i<=1000000;i++){
            if(i>=3)
                if(a[i] && a[i-1] && a[i-2]){
                    a[i]--;a[i-1]--;a[i-2]--;
                    cnt++; 
                }
            cnt += a[i]/2;
            a[i] %= 2;
        }
        printf("%d\n",cnt);
    }
    return 0;
} 

08

开始打表的时候发现如果a是奇数的时候肯定是1

然后a是偶数的时候,2的因子个数很多,枚举一下就行了,后面的就为0了。

开始打表发现, a ≥ n a \geq n an的时候,几乎是所有的偶数,无脑了几发。发现 a &lt; n a &lt; n a<n的时候答案不对。事实上,枚举一下较小的部分。加上后面0的部分。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll n,a;

ll power(ll a,ll b,ll mod){
    if(b==0) return 1ll;
    ll ret = power(a,b/2,mod);
    ret = ret * ret % mod;
    if(b&1)
        return ret*a%mod;
    return ret;
}

ll up(ll n,ll a){
    return (n + a - 1) / a;
}

int main(){
    //freopen("output.txt","w",stdout);
    while(~scanf("%lld%lld",&n,&a)){
        if(a&1){
            puts("1");
            continue;
        }
        ll mod = 1ll<<n; 
        ll res = 0;
        for(int i=2;i<=n;i+=2)
            if(power(a,i,mod) == power(i,a,mod)) res++;
        res += (1<<n) >> (up(n,a));
        res -= n >> (up(n,a));
        printf("%d\n",res);
    }
    return 0;
} 

#10

【bzoj3261】最大异或和
首先,如果是区间异或的话,可以用可持续化Trie树。对于树上的可以用dfs序做。查询就查询in[u]到out[u]的的区间就行了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long 
#define N 200005
#define inf 2000000000
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int bin[30];
int n,m;
int a[N],b[N],root[N];
struct trie{
    int cnt;
    int ch[N*30][2],sum[N*30];
    void init(){
        cnt = 0;
        memset(ch,0,sizeof ch);
        memset(sum,0,sizeof sum);
    }
    int insert(int x,int val){
        int tmp,y;tmp=y=++cnt;
        for(int i=29;i>=0;i--)
        {
            ch[y][0]=ch[x][0];ch[y][1]=ch[x][1];
            sum[y]=sum[x]+1;
            int t=val&bin[i];t>>=i;
            x=ch[x][t];
            ch[y][t]=++cnt;
            y=ch[y][t];
        }
        sum[y]=sum[x]+1;
        return tmp;
    }
    int query(int l,int r,int val){
        int tmp=0;
        for(int i=29;i>=0;i--)
        {
            int t=val&bin[i];t>>=i;
            if(sum[ch[r][t^1]]-sum[ch[l][t^1]])
                tmp+=bin[i],r=ch[r][t^1],l=ch[l][t^1];
            else r=ch[r][t],l=ch[l][t];
        }
        return tmp;
    }
}trie;

int in[N],out[N],cnt;

vector<int> e[N];

void dfs(int id,int fa){
    in[id] = ++cnt;
    root[cnt] = trie.insert(root[cnt-1],a[id]);
    for(auto ep:e[id]){
        if(ep == fa) continue;
        dfs(ep,id);
    }
    out[id]=cnt;
}

int main(){
    bin[0]=1;for(int i=1;i<=30;i++)bin[i]=bin[i-1]<<1;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++) e[i].clear();
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=2;i<=n;i++){
            int v; 
            scanf("%d",&v);
            e[v].push_back(i);
        }
        cnt=0;
        trie.init(); 
        dfs(1,0);
        int u,x;
        //for(int i=1;i<=n;i++){
        //    printf("in[%d],out[%d] %d\n",in[i],out[i],i);
        //}
        //cout<<root[4]<<endl; 
        while(m--){
            scanf("%d%d",&u,&x);
            printf("%d\n",trie.query(root[in[u]-1],root[out[u]],x));
        }
    }
    return 0;
}

哇哦

这里写图片描述

这里写图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值