2019 ICPC Asia Yinchuan Regional

2019 ICPC Asia Yinchuan Regional

\(A. Girls Band Party\)

\(B. So Easy\)
\(n\)\(n\)列分别加上一个\(\ge 0\)的数,已知其他位置的数,求\(x\)\(y\)列处的数是多少
每行每列全都减去当前行或列最小的那个数,第\(x\)行减去的值和第\(y\)列减去的值的和就是答案
相当于原来操作的逆操作

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
int n,A[MAXN][MAXN];
void solve(){
    cin >> n;
    int x,y,ret=0;
    for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++){
        cin >> A[i][j];
        if(A[i][j]==-1) x = i, y = j;
    }
    for(int i = 1; i <= n; i++){
        int minn = 1e7;
        for(int j = 1; j <= n; j++) if(A[i][j]>=0) minn = min(minn,A[i][j]);
        for(int j = 1; j <= n; j++) A[i][j] -= minn;
        if(i==x) ret+=minn;
    }
    for(int i = 1; i <= n; i++){
        int minn = 1e7;
        for(int j = 1; j <= n; j++) if(A[j][i]>=0) minn = min(minn,A[j][i]);
        for(int j = 1; j <= n; j++) A[j][i] -= minn;
        if(i==y) ret+=minn;
    }
    cout << ret << endl;
}
int main(){
    ____();
    solve();    
    return 0;
}

\(C. Image Processing\)

\(D. Easy Problem\)

\[计算\sum (a_1\cdot a_2 \cdot a_3 \cdots a_n)^k\ 其中gcd(a_1,a_2,a_3,\cdots,a_n)=d且a_i\le m \]

转化一下,就是计算:

\[(d^k)^n\sum (b_1\cdot b_2 \cdot b_3 \cdots b_n)^k\ 其中gcd(b_1,b_2,b_3,\cdots,b_n)=1且b_i\le \lfloor \frac{m}{d}\rfloor \]

考虑如何计算\(\sum (x_1\cdot x_2\cdot x_3\cdots x_n)^k\),其中\(1\le x_i\le m\)
\(\sum (x_1\cdot x_2\cdot x_3\cdots x_n)^k = \sum (x_1^k\cdot x_2^k\cdot x_3^k\cdots x_n^k) = (\sum_{i=1}^{m}i^k)^n\)
然后我们需要去掉\(gcd(b_1,b_2,b_3,\cdots,b_n)\ne 1\)的情况,这是个和约数相关的容斥原理,容斥系数就是莫比乌斯函数
所以最后可以得到:

\[resault = (d^k)^n\cdot \sum_{i=1}^{\lfloor \frac{m}{d}\rfloor} \mu (i)((\sum_{j=1}^{\lfloor \frac{m}{id}\rfloor}j^k)(i^k))^n \]

内部可以用前缀和预处理加上快速幂复杂度大概是\(O(Tm\log(MOD))\)
注意这里的模数\(59964251\)不是质数,大数幂的时候需要用扩展欧拉定理


//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
using LL = int_fast64_t;
const LL MOD = 59964251;
const LL phi = 59870352;
char n[MAXN];
LL m, d, k, pre[MAXN];
int mu[MAXN],npm[MAXN];
vector<int> prime;
LL qpow(LL a, LL b){
    LL ret = 1;
    while(b){
        if(b&1) ret = ret * a % MOD;
        b >>= 1;
        a = a * a % MOD;
    }
    return ret;
}
void preprocess(){
    mu[1] = 1;
    for(int i = 2; i < MAXN; i++){
        if(!npm[i]) prime.emplace_back(i), mu[i] = -1;
        for(int j = 0; j < (int)prime.size(); j++){
            if(i*prime[j]>=MAXN) break;
            npm[i*prime[j]] = true;
            mu[i*prime[j]] = -mu[i];
            if(i%prime[j]==0){
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
}
void solve(){
    cin >> n >> m >> d >> k;
    LL pw = 0;
    for(int i = 0, len = strlen(n); i < len; i++) pw = (pw * 10 + n[i]-'0') % phi;     //扩展欧拉定理
    pw += phi;
    k = k % phi + phi;
    for(int i = 1; i <= m; i++) pre[i] = (pre[i-1] + qpow(i,k)) % MOD;
    LL ret = 0;
    for(int i = 1; i <= m / d; i++) ret = (ret + mu[i] * qpow((pre[m/(i*d)]*qpow(i,k))%MOD,pw)) % MOD;
    ret = ret * qpow(qpow(d,k),pw) % MOD;
    if(ret<0) ret += MOD;
    cout << ret << endl;
}
int main(){
    ____();
    int T;
    preprocess();
    for(cin >> T; T; T--) solve();
    return 0;
}

\(E. XOR Tree\)

\(F. Function!\)

\[计算 \sum_{a=2}^{n}(a\sum_{b=a}^{n}\lfloor\log_{a}b\rfloor),n\le 10^{12} \]

发现\(a>\lfloor \sqrt{n}\rfloor\)时,后面的和式变成了\(a\sum_{b=a}^{n}1=a\cdot(n-a+1)\)
所以而在\(\sqrt{n}\)之前的可以枚举\(\lfloor\log_ab\rfloor\)来计算,式子变成:

\[\sum_{a=2}^{\lfloor \sqrt{n}\rfloor}(a\sum_{b=a}^{n} \lfloor\log_{a}b\rfloor)+\sum_{a=\lfloor\sqrt{n}\rfloor +1}^{n}(a\cdot (n-a+1)) \]

复杂度\(O(\sqrt{n}\log{n})\)
计算\(\sum_{x=1}^{n}x^2\)的公式是\(\frac{n\cdot (n+1)\cdot (2\cdot n+1)}{6}\)

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const LL MOD = 998244353;
LL qpow(LL a, LL b){
    LL ret = 1;
    while(b){
        if(b&1) ret = ret * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ret;
}
LL inv(LL x){ return qpow(x,MOD-2); }
LL n;
int main(){
    ____();
    cin >> n;
    int sqt = (int)sqrt(n);
    LL ret = 0;
    for(int a = 2; a <= sqt; a++){
        LL pre = a;
        int add = 0;
        while(true){
            add++;
            LL now = min(n,pre*a-1);
            ret = (ret + (now-pre+1) * add * a) % MOD;
            if(now==n) break;
            pre *= a;
        }
    }
    LL x = sqt + 1, m = n % MOD;
    ret = (ret + (m+1) % MOD * (x+m) % MOD * (m-x+1) % MOD * inv(2)) % MOD;
    ret = (ret - m * (m+1) % MOD * (2*m+1) % MOD * inv(6) % MOD + (x-1) * x % MOD * (2*x-1) % MOD * inv(6)) % MOD;
    if(ret < 0) ret += MOD;
    cout << ret << endl;
    return 0;
}

\(G. Pot!!\)
\(10\)以内的质数只有\(2,3,5,7\),线段树维护区间内四个质数出现次数的最大值即可
更新的时候区间内把\(x\)分解质因子之后区间更新

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
struct SegmentTree{
    int maxx[MAXN<<2][4],lazy[MAXN<<2][4];
    int l[MAXN<<2],r[MAXN<<2];
    #define ls(rt) rt << 1
    #define rs(rrt) rt << 1 | 1
    void pushup(int rt){
        for(int i = 0; i < 4; i++) maxx[rt][i] = max(maxx[ls(rt)][i],maxx[rs(rt)][i]);
    }
    void pushdown(int rt){
        for(int i = 0; i < 4; i++){
            if(!lazy[rt][i]) continue;
            maxx[ls(rt)][i] += lazy[rt][i]; lazy[ls(rt)][i] += lazy[rt][i];
            maxx[rs(rt)][i] += lazy[rt][i]; lazy[rs(rt)][i] += lazy[rt][i];
            lazy[rt][i] = 0;
        }
    }
    void build(int L, int R, int rt = 1){
        l[rt] = L, r[rt] = R;
        if(L+1==R) return;
        int mid = (L+R) >> 1;
        build(L,mid,ls(rt)); build(mid,R,rs(rt));
    }
    void update(int L, int R, int tg, int rt = 1){
        if(L>=r[rt] or l[rt]>=R) return;
        if(L<=l[rt] and r[rt]<=R){
            maxx[rt][tg]++;
            lazy[rt][tg]++;
            return;
        }
        pushdown(rt);
        update(L,R,tg,ls(rt)); update(L,R,tg,rs(rt));
        pushup(rt);
    }
    int query(int L, int R, int tg, int rt = 1){
        if(L>=r[rt] or l[rt]>=R) return 0;
        if(L<=l[rt] and r[rt]<=R) return maxx[rt][tg];
        pushdown(rt);
        return max(query(L,R,tg,ls(rt)),query(L,R,tg,rs(rt)));
    }
}ST;
int n,m;
int main(){
    scanf("%d %d",&n,&m);
    ST.build(1,n+1);
    char op[20];
    for(int i = 1; i <= m; i++){
        scanf("%s",op);
        if(op[1]=='A'){
            int l, r, ret = 0; scanf("%d %d",&l,&r);
            r++;
            for(int k = 0; k < 4; k++) ret = max(ret,ST.query(l,r,k));
            printf("ANSWER %d\n",ret);
        }
        else{
            int l, r, x; scanf("%d %d %d",&l,&r,&x);
            r++;
            while(x-1 and x%2==0) x/=2, ST.update(l,r,0);
            while(x-1 and x%3==0) x/=3, ST.update(l,r,1);
            while(x-1 and x%5==0) x/=5, ST.update(l,r,2);
            while(x-1 and x%7==0) x/=7, ST.update(l,r,3);
        }
    }
    return 0;
}

\(H. Delivery Route\)
BZOJ2200
Dijkstra不能跑负权图 所以可以先缩点,缩点完之后就是一个DAG,其中可以对每个连通块跑Dijkstra

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
const int INF = 0x3f3f3f3f;
int n,x,y,s,sccid[MAXN],sid,deg[MAXN],dist[MAXN];
bool vis[MAXN];
vector<int> scc[MAXN];
int Stk[MAXN], tp;
bool instk[MAXN];
int top(){ return Stk[tp]; }
void pop(){ instk[Stk[tp--]] = false; }
void push(int x){ instk[Stk[++tp]=x] = true; }
bool check(int x){ return instk[x]; }
struct Graph{
    int to[MAXN<<2],nxt[MAXN<<2],w[MAXN<<2],head[MAXN],tot;
    Graph(){}
    void ADDEDGE(int u, int v, int x){
        tot++;
        to[tot] = v; nxt[tot] = head[u]; w[tot] = x;
        head[u] = tot;
    }
}G;
void gao(int u, int id){
    sccid[u] = id;
    scc[id].push_back(u);
    for(int i = G.head[u]; i; i = G.nxt[i]) if(!sccid[G.to[i]]) gao(G.to[i],id);
}
void dfs(int u){
    vis[u] = true;
    for(int i = G.head[u]; i; i = G.nxt[i]) if(!vis[G.to[i]]) dfs(G.to[i]);
}
void rebuild(){
    for(int u = 1; u <= n; u++){
        if(!vis[u]) continue;
        for(int i = G.head[u]; i; i = G.nxt[i]){
            int v = G.to[i];
            if(!vis[v] or sccid[u]==sccid[v]) continue;
            deg[sccid[v]]++;
        }
    }
}
queue<int> que;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
void Dijkstra(int ss){
    for(int v : scc[ss]) if(dist[v]!=INF) pq.push(make_pair(dist[v],v));
    while(!pq.empty()){ 
        auto p = pq.top();
        pq.pop();
        int u = p.second;
        if(dist[u]!=p.first) continue;
        for(int i = G.head[u]; i; i = G.nxt[i]){
            int v = G.to[i], w = G.w[i];
            if(!vis[v]) continue;
            if(sccid[v]!=sccid[u]) if(!--deg[sccid[v]]) que.push(sccid[v]);
            if(dist[v]>dist[u]+w){
                dist[v] = dist[u] + w;
                if(sccid[v]==sccid[u]) pq.push(make_pair(dist[v],v));
            }
        }
    }
}
void solve(){
    memset(dist,0x3f,sizeof(dist));
    dist[s] = 0;
    que.push(sccid[s]);
    while(!que.empty()){
        int ss = que.front();
        que.pop();
        Dijkstra(ss);
    }
    for(int i = 1; i <= n; i++){
        if(dist[i]==INF) puts("NO PATH");
        else printf("%d\n",dist[i]);
    }
}
int main(){
    scanf("%d %d %d %d",&n,&x,&y,&s);
    for(int i = 1; i <= x; i++){
        int u, v, w; scanf("%d %d %d",&u,&v,&w);
        G.ADDEDGE(u,v,w); G.ADDEDGE(v,u,w);
    }
    for(int i = 1; i <= n; i++) if(!sccid[i]) gao(i,++sid);
    for(int i = 1; i <= y; i++){
        int u, v, w; scanf("%d %d %d",&u,&v,&w);
        G.ADDEDGE(u,v,w);
    }
    dfs(s);
    rebuild();
    solve();
    return 0;
}

\(I. Base62\)
大数的进制转换,用不想写c++,那就用直接Java

import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
    private static Scanner cin = new Scanner(new BufferedInputStream(System.in));
    private static PrintWriter cout = new PrintWriter(System.out,true);
    private static InputStream inputstream = System.in;
    public static void main(String[] args){
        Task solver = new Task();
        int TaskCase = 1;
        while(TaskCase--!=0){
            solver.solve();cout.flush();
        }
    }
    private static class Task{
        HashMap<Character,Integer> map1 = new HashMap<>();
        HashMap<Integer,Character> map2 = new HashMap<>();
        public void solve(){
            for(int i = 0; i <= 9; i++){
                map1.put((char)(i+(int)('0')),i);
                map2.put(i,(char)(i+(int)('0')));
            }
            for(int i = (int)('A'); i <= (int)('Z'); i++){
                map1.put((char)(i),i-(int)('A')+10);
                map2.put(i-(int)('A')+10,(char)(i));
            }
            for(int i = (int)('a'); i <= (int)('z'); i++){
                map1.put((char)(i),i-(int)('a')+36);
                map2.put(i-(int)('a')+36,(char)(i));
            }
            int base1 = cin.nextInt(), base2 = cin.nextInt();
            String str1 = cin.next();
            BigInteger bs1 = BigInteger.valueOf(base1);
            BigInteger bs2 = BigInteger.valueOf(base2);
            BigInteger base10 = BigInteger.ZERO;
            for(int i = 0; i < str1.length(); i++){
                base10 = base10.multiply(bs1).add(BigInteger.valueOf(map1.get(str1.charAt(i))));
            }
            ArrayList<Integer> arr = new ArrayList<>();
            if(base10.equals(BigInteger.ZERO)) arr.add(0);
            while(!(base10.equals(BigInteger.ZERO))){
                arr.add(base10.mod(bs2).intValue());
                base10 = base10.divide(bs2);
            }
            for(int i = arr.size() - 1; i >= 0; i--) cout.write(map2.get(arr.get(i)));
        }
    }
}

\(J. Toad’s Travel\)

\(K. Largest Common Submatrix\)
由于\(AB\)两个矩阵中每个数都只出现一次,所以我们新建一个矩阵\(C\),矩阵里存放\(A\)中每个位置\(x,y\)对应的数在B矩阵中的位置和在\(A\)矩 阵中的位置的差值,现在问题转化为找一个最大的子矩阵\(Mat\)使得这个矩阵中的所有值相同,单调栈做就好了

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
int n,m,A[MAXN][MAXN],B[MAXN][MAXN],f[MAXN][MAXN],l[MAXN],r[MAXN];
pair<int,int> pos[MAXN*MAXN],mat[MAXN][MAXN];
pair<int,int> operator - (const pair<int,int> &lhs, const pair<int,int> &rhs){
    return make_pair(lhs.first-rhs.first,lhs.second-rhs.second);
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d",&A[i][j]);
    for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d",&B[i][j]), pos[B[i][j]] = make_pair(i,j);
    for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) mat[i][j] = make_pair(i,j) - pos[A[i][j]];
    for(int i = 1; i <= n; i++) for(int j = m; j >= 1; j--){
        f[i][j] = 1; if(j==m) continue;
        if(mat[i][j]==mat[i][j+1]) f[i][j] += f[i][j+1];
    }
    int ret = 0;
    for(int i = 1; i <= m; i++){
        stack<int> stk;
        memset(l,0,sizeof(l)); memset(r,0,sizeof(r));
        for(int j = 1; j <= n; j++){
            if(!stk.empty()){
                if(mat[j][i]!=mat[j-1][i]){
                    while(!stk.empty()){
                        r[stk.top()] = j - 1;
                        stk.pop();
                    }
                }
            }
            while(!stk.empty() and f[j][i]<f[stk.top()][i]){
                l[j] = l[stk.top()];
                r[stk.top()] = j - 1;
                stk.pop();
            }
            if(!l[j]) l[j] = j;
            stk.push(j);
        }
        while(!stk.empty()){
            r[stk.top()] = n;
            stk.pop();
        }
        for(int j = 1; j <= n; j++) ret = max(ret,(r[j]-l[j]+1)*f[j][i]);
    }
    cout << ret << endl;
    return 0;
}

\(L. Xian Xiang\)

\(M. Crazy Cake\)

\(N. Fibonacci Sequence\)
输出\(1,1,2,3,5\)
python写一行就完了

print(1,1,2,3,5)
posted @ 2020-04-25 14:59  _kiko  阅读(263)  评论(0编辑  收藏  举报