《2017ACM/ICPC广西邀请赛-重现赛》

A:暴力就行

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
typedef tuple<int,int,int> tu;
const int N = 3e5 + 5;
const int M = 1e3 + 5;
const double eps = 1e-10;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
    int f = 1;int x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

LL qucik_mi(LL a,LL b) {
    LL re = 1;
    while(b) {
        if(b & 1) re = re * a;
        a = a * a;
        b >>= 1;
    }
    return re;
}
void solve() {
    LL n;
    while(~scanf("%lld",&n)) {  
        LL ans = 0;
        for(int i = 1;i <= 15;++i) {
            LL ma = qucik_mi(i,i);
            if(ma <= n) ans++;
        }
        printf("%lld
",ans);
    }
} 
int main() {    
    solve();
  //  system("pause");
    return 0;
}
View Code

B:这个题还是很不错的。

第一眼以为是二维的线段树,但是发现空间怎么都开不出来,而且要统计不同的颜色数。

观察这个矩阵可以发现,左边界都是在y轴上,那么我们要查询一个颜色在这里,就只需要找x最小的一个在1 ~ x1里。

那么对于y轴上我们就在y1 ~ y2里找。

那么方案就出来了,我们维护一棵y轴上的线段树,每个点维护最小的横坐标值。

因为只有50种,所以我们维护50课线段树就行。

但是如果真的维护50棵1 ~ 1e6的线段树,那空间肯定开不出来。

但是我们可以发现询问并不是很多,所以考虑动态开点维护线段树,一个点大概Logn的空间。

总空间m long n。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 2e5 + 5;
const double eps = 1e-10;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
    int f = 1;int x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

int rt[55],top = 0,f = 0;
struct {int L,r,mi;}node[N * 20];
void Pushup(int idx) {
    int l = node[idx].L,r = node[idx].r;
    if(l != 0) node[idx].mi = min(node[idx].mi,node[l].mi);
    if(r != 0) node[idx].mi = min(node[idx].mi,node[r].mi);
}
void build(int L,int r,int y,int x,int &idx) {
    if(idx == 0) {
        idx = ++top;
        node[idx].mi = x;
    }
    if(L == r) {
        node[idx].mi = min(node[idx].mi,x);
        return ;
    }
    int mid = (L + r) >> 1;
    if(mid >= y) build(L,mid,y,x,node[idx].L);
    else build(mid + 1,r,y,x,node[idx].r);
    Pushup(idx);
}
void query(int L,int r,int y1,int y2,int val,int idx) {
    if(idx == 0 || f) return ;
    if(L >= y1 && r <= y2) {
        if(node[idx].mi <= val) f = 1;
        return ;
    }
    int mid = (L + r) >> 1;
    if(mid >= y1) query(L,mid,y1,y2,val,node[idx].L);
    if(mid < y2) query(mid + 1,r,y1,y2,val,node[idx].r);
}
void solve() { 
    while(1) {
        int op;op = read();
        if(op == 3) break;
        if(op == 0) {
            for(int i = 0;i <= 50;++i) rt[i] = 0;
            for(int i = 1;i <= top;++i) node[i].L = node[i].r = 0,node[i].mi = INF;
            top = 0;
        }
        else if(op == 1) {
            int x,y,c;x = read(),y = read(),c = read();
            build(1,1000000,y,x,rt[c]);
        } 
        else {
            int x,y,c;x = read(),y = read(),c = read();
            int ans = 0;
            for(int i = 0;i <= 50;++i) {
                f = 0;
                query(1,1000000,y,c,x,rt[i]);
                if(f) ans++;
            }
            printf("%d
",ans);
        }
    }

} 
int main() {    
    solve();
   // system("pause");
    return 0;
}
View Code

C:三元环计数。(1:度不相同则,小度点向大度点连边,否则小编号向大编号连)

算出每条边在几个三元环里,然后求一下方案数即可。

需要注意的是,因为我们重构的是有向图,所以对于一个三元环,三条边都要加上1。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
const double eps = 1e-10;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
    int f = 1;int x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

int deg[N];
vector<pii> G[N];
pii px[M],py[M];
int vis[N],cnt[M],tag[N];
void solve() { 
    int n,m;
    while(~scanf("%d %d",&n,&m)) {
        for(int i = 1;i <= n;++i) deg[i] = 0,G[i].clear(),vis[i] = tag[i] = 0;
        for(int i = 1;i <= m;++i) {
            cnt[i] = 0;
            deg[px[i].first = read()]++,deg[py[i].first = read()]++;
            px[i].second = py[i].second = i;
        }
        for(int i = 1;i <= m;++i) {
            if(deg[px[i].first] == deg[py[i].first]) {
                G[min(px[i].first,py[i].first)].push_back(pii{max(px[i].first,py[i].first),i});
            }
            else if(deg[px[i].first] < deg[py[i].first]) G[px[i].first].push_back(pii{py[i].first,i});
            else G[py[i].first].push_back(pii{px[i].first,i});
        }
        for(int i = 1;i <= m;++i) {
            for(auto v : G[px[i].first]) {
                vis[v.first] = px[i].first;
                tag[v.first] = v.second;
            }
            for(auto v : G[py[i].first]) {
                if(vis[v.first] == px[i].first) {
                    cnt[v.second]++;    
                    cnt[i]++;
                    cnt[tag[v.first]]++;
                }
            }
        }
        LL ans = 0;
        for(int i = 1;i <= m;++i) ans += 1LL * cnt[i] * (cnt[i] - 1) / 2;
        printf("%lld
",ans);
    }
} 
int main() {    
    solve();
    //system("pause");
    return 0;
}
View Code

D:这题很明显是找到递推式然后矩阵快速幂加速下。

但是在纸上推了很久的规律都没有找到。

这里看到了别人的一种很不错的做法:暴力dfs出前几项。

然后不断暴力枚举系数,从1个开始加。

当然这样如果递推式子涉及到后面很多项,复杂度容易超时。

优化:只枚举系数个数,然后高斯消元解方程就可以了。

当然上面这两种方案只满足都是线性递推的情况下。

不过矩阵快速幂一般都是线性的系数,所以很什么问题。

这里还有个问题,负数做乘法,会导致问题,因为存在负数的系数。

所以每次都要把负数转化成正数。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
const double eps = 1e-10;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
    int f = 1;int x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

bool vis[5][15];
void dfs(int x,int y,int sum,int n) {
    if(sum == 4 * n) {
        //ans++;
        return ;
    }
    if(vis[x][y]) {
        if(x == 4) dfs(1,y + 1,sum,n);
        else dfs(x + 1,y,sum,n);
    }
    else {
        if(x + 1 <= 4 && vis[x + 1][y] == 0) {
            vis[x + 1][y] = 1;
            vis[x][y] = 1;
            dfs(x + 1,y,sum + 2,n);
            vis[x + 1][y] = 0;
            vis[x][y] = 0;
        }   
        if(y + 1 <= n && vis[x][y + 1] == 0) {
            vis[x][y + 1] = 1;
            vis[x][y] = 1;
            if(x == 4) dfs(1,y + 1,sum,n);
            else dfs(x + 1,y,sum + 2,n);
            vis[x][y + 1] = 0;
            vis[x][y] = 0;
        }
    }
}
/*
1 5 11 36 95 281 781 2245 6336 18061
dp[i] = dp[i - 1] + 5 * dp[i - 2] + dp[i - 3] - dp[i - 4]
*/
int dp[15];
void init() {
    //dfs(1,1,0,10);
    //dbg(ans);
    dp[1] = 1,dp[2] = 5,dp[3] = 11,dp[4] = 36,dp[5] = 95,dp[6] = 281,dp[7] = 781,dp[8] = 2245,dp[9] = 6336,dp[10] = 18061;
    for(int i = -10;i <= 10;++i) {   
        for(int j = -10;j <= 10;++j) {
            for(int a = -10;a <= 10;++a) {
                for(int b = -10;b <= 10;++b) {
                    int f = 0;
                    for(int k = 5;k <= 10;++k) {
                        if(dp[k] != i * dp[k - 1] + j * dp[k - 2] + a * dp[k - 3] + b * dp[k - 4]) f = 1;
                    }
                    if(f == 0) printf("%d %d %d %d
",i,j,a,b);
                }
            }
        }
    }
}

struct Mat{
    LL m[5][5];
    Mat operator * (const Mat a)const{
        Mat c;memset(c.m,0,sizeof(c.m));
        for(int i = 1;i <= 4;++i) {
            for(int j = 1;j <= 4;++j) {
                for(int k = 1;k <= 4;++k) {
                    c.m[i][j] = ADD(c.m[i][j],MUL(m[i][k],a.m[k][j]));
                    c.m[i][j] = ADD(c.m[i][j],Mod);
                }
            }
        }
        return c;
    }
};
Mat quick_mi(Mat a,LL b) {
    Mat res;memset(res.m,0,sizeof(res.m));
    for(int i = 1;i <= 4;++i) res.m[i][i] = 1;
    while(b) {
        if(b & 1) res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}
void solve() { 
    LL n;
    while(~scanf("%lld",&n)) {
        Mat a;memset(a.m,0,sizeof(a.m));
        a.m[1][1] = 1,a.m[1][2] = 5,a.m[1][3] = 1,a.m[1][4] = -1;
        a.m[2][1] = 1,a.m[3][2] = 1,a.m[4][3] = 1;
        Mat ans;memset(ans.m,0,sizeof(a.m));
        ans.m[1][1] = 1,ans.m[2][1] = 5,ans.m[3][1] = 11,ans.m[4][1] = 36;
        a = quick_mi(a,n + 3);
        ans = a * ans;
        printf("%lld
",ans.m[1][1]);
    }
} 
int main() {    
    //init();
    solve();
    //system("pause");
    return 0;
}
View Code

E:统计一下二进制就行。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
const double eps = 1e-10;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
    int f = 1;int x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

int a[N],bit[30];
void solve() { 
    int n,q;
    while(~scanf("%d %d",&n,&q)) {
        memset(bit,0,sizeof(bit));
        int ans3 = 0;
        for(int i = 1;i <= n;++i) {
            a[i] = read();
            ans3 ^= a[i];
            for(int j = 0;j < 30;++j) {
                int g = (a[i] >> j) & 1;
                if(g == 1) bit[j]++;
            }
        }
        while(q--) {
            int p;p = read();
            int ma3 = ans3 ^ a[p];
            int ma1 = 0,ma2 = 0;
            for(int i = 0;i < 30;++i) {
                int g = (a[p] >> i) & 1;
                if(g == 0) {
                    if(bit[i] == n - 1) ma1 += (1 << i);
                    if(bit[i] > 0) ma2 += (1 << i);
                }
                else {
                    if(bit[i] == n) ma1 += (1 << i);
                    if(bit[i] > 1) ma2 += (1 << i);
                }
            }
            printf("%d %d %d
",ma1,ma2,ma3);
        }
    
    }
} 
int main() {    
    solve();
    //system("pause");
    return 0;
}
View Code

F:这个题就是题意比较难读。

就是给你一个连通图,问你最小删多少的边的价值,使这个图无环。

我们可以考虑删完之后的图,我们要删的尽量小,那就是要让留下来的这个树(无环图,那就可以看成树)的总权值尽可能大。

那么就是求一棵最大生成树。

因为自己没写,贴一下队友的代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define Endl endl
struct X{
    int a,b,val;
}r[200050];
int ef[100050];
int find(int g){return ef[g]==g?g:ef[g]=find(ef[g]);}
bool cmp(X a,X b){return a.val>b.val;}
int main()
{
    ios::sync_with_stdio(false);
    int a,b,c,d,sum,s1,cnt;
    while(cin>>a>>b){
        cnt=s1=sum=0;
        for(int i=1;i<=a;i++){
            cin>>c>>c;
            ef[i]=i;
        }
        for(int i=0;i<b;i++){
            cin>>r[i].a>>r[i].b>>r[i].val;
            s1+=r[i].val;
        }
        sort(r,r+b,cmp);
        for(int i=0;i<b;i++){
            c=find(r[i].a);
            d=find(r[i].b);
            if(c!=d){
                sum+=r[i].val;
                cnt++;
                ef[max(c,d)]=min(c,d);
            }
        }
        cout<<b-cnt<<' '<<s1-sum<<endl;
    }
    return 0;
}
View Code

G:贪心一下就行。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e6 + 5;
const int M = 2e5 + 5;
const double eps = 1e-10;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
    int f = 1;int x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

int a[N];
int cnt[N];
void solve() { 
    int n;
    while(~scanf("%d",&n)) {
        memset(cnt,0,sizeof(cnt));
        for(int i = 1;i <= n;++i) a[i] = read(),cnt[a[i]]++;
        sort(a + 1,a + n + 1);
        LL ans = 0;
        int len = unique(a + 1,a + n + 1) - a - 1;
        for(int i = 1;i <= len;++i) {
            while(cnt[a[i]] >= 3) {
                ans += 1;
                cnt[a[i]] -= 2;
            }
            if(cnt[a[i]] == 1) {
                if(a[i - 1] == a[i] - 1 && a[i] + 1 == a[i + 1] && cnt[a[i - 1]] > 0 && cnt[a[i + 1]] > 0) {
                    ans++;
                    cnt[a[i - 1]]--;
                    cnt[a[i]]--;
                    cnt[a[i] + 1]--;
                }  
            }
            else if(cnt[a[i]] == 2){
                if(i >= 2) {
                    if(a[i - 2] == a[i - 1] - 1 && a[i - 1] == a[i] - 1 && a[i + 1] == a[i] + 1 && a[i + 2] == a[i + 1] + 1) {
                        if(cnt[a[i - 2]] == 1 && cnt[a[i - 1]] == 1 && cnt[a[i + 1]] > 0 && cnt[a[i + 2]] > 0) {
                            ans += 2;
                            cnt[a[i - 2]]--;
                            cnt[a[i - 1]]--;
                            cnt[a[i]] -= 2;
                            cnt[a[i + 1]]--;
                            cnt[a[i + 2]]--;
                        }
                        else ans++,cnt[a[i]] -= 2;
                    }
                    else ans++,cnt[a[i]] -= 2;
                }
                else ans++,cnt[a[i]] -= 2;
            }
        }
        printf("%d
",ans);

    }

} 
int main() {    
    solve();
    //system("pause");
    return 0;
}
View Code

J:这题也挺不错的。

一开始想的是树上合并01字典树。

但是空间开不出来。

然后就直接dsu on tree维护01字典树。

但是这里删点之后top++会可能导致超空间,re。

最后写了个队列回收之间的节点才过了。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
const double eps = 1e-10;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline int read() {
    int f = 1;int x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

int val[N],son[N],sz[N],ans[N],top = 0,Son = 0;
vector<int> G[N];
vector<pii> vec[N];
queue<int> Q;
int tree[N * 50][2],cnt[N * 50][2];
void Insert(int ma) {
    int x = 0;
    for(int i = 29;i >= 0;--i) {
        int g = (ma >> i) & 1;
        if(tree[x][g] == 0) {
            if(top >= N * 49) {
                tree[x][g] = Q.front();
                Q.pop();
            }
            else {
                tree[x][g] = ++top;
            }
            cnt[x][g] = 1;
        }
        else cnt[x][g]++;
        x = tree[x][g];
    }
}
void Delete(int ma) {
    int x = 0;
    for(int i = 29;i >= 0;--i) {
        int g = (ma >> i) & 1;
        if(tree[x][g] == 0) return ;
        int y = tree[x][g];
        cnt[x][g]--;
        if(cnt[x][g] == 0) {
            Q.push(tree[x][g]);
            tree[x][g] = 0;
        }
        x = y;
    }
}
int query(int ma) {
    int x = 0;
    int ans = 0;
    for(int i = 29;i >= 0;--i) {
        int g = (ma >> i) & 1;
        if(tree[x][g ^ 1] == 0) {
            x = tree[x][g];
        }
        else {
            ans += (1 << i);
            x = tree[x][g ^ 1];
        }
    }
    return ans;
}
void dfs(int u) {
    sz[u] = 1;
    for(auto v : G[u]) {
        dfs(v);
        sz[u] += sz[v];
        if(sz[v] > sz[son[u]]) son[u] = v;
    }
}
void solve(int u,int id) {
    if(id == 1) Insert(val[u]);
    else Delete(val[u]);
    for(auto v : G[u]) {
        if(v == Son) continue;
        solve(v,id);
    }
}
void dfs1(int u,int opt) {
    for(auto v : G[u]) {
        if(v == son[u]) continue;
        dfs1(v,0);
    }
    if(son[u]) dfs1(son[u],1),Son = son[u];
    solve(u,1);
    Son = 0;
    for(auto v : vec[u]) {
        ans[v.first] = query(v.second);
    }
    if(opt == 0) solve(u,-1);
}
void solve() { 
    int n,q;
    while(~scanf("%d %d",&n,&q)) {
        top = 0;
        while(!Q.empty()) Q.pop();
        memset(cnt,0,sizeof(cnt));
        memset(tree,0,sizeof(tree));
        for(int i = 1;i <= n;++i) {
            val[i] = read();
            G[i].clear();
            vec[i].clear();
            son[i] = 0;
        }
        for(int i = 1;i < n;++i) {
            int x;x = read();
            G[x].push_back(i + 1);
        }
        dfs(1);
        for(int i = 1;i <= q;++i) {
            int u,x;u = read(),x = read();
            vec[u].push_back(pii{i,x});
        }
        dfs1(1,0);
        for(int i = 1;i <= q;++i) printf("%d
",ans[i]);
    }
} 
int main() {    
    solve();
    //system("pause");
    return 0;
}
/*
7 6
4 7 2 2 1 9 6
1 1 2 2 3 4
2 4
2 5
3 1
3 6
1 7
7 2
*/
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/15292711.html