2022SDNU-ACM結(jié)訓(xùn)賽題解-創(chuàng)新互聯(lián)

首先感謝一下各位出題人的精心準(zhǔn)備、驗(yàn)題人的辛勤付出、以及選手的積極參加

創(chuàng)新互聯(lián)專注骨干網(wǎng)絡(luò)服務(wù)器租用10年,服務(wù)更有保障!服務(wù)器租用,四川服務(wù)器托管 成都服務(wù)器租用,成都服務(wù)器托管,骨干網(wǎng)絡(luò)帶寬,享受低延遲,高速訪問。靈活、實(shí)現(xiàn)低成本的共享或公網(wǎng)數(shù)據(jù)中心高速帶寬的專屬高性能服務(wù)器。題解 Problem A 柳予欣的歸來(lái)【數(shù)學(xué)】

出題人: bhq

沒想到一血是被打完山大的??捅荣惡髞?lái)結(jié)訓(xùn)賽玩的wyx拿走的!

題目描述:

計(jì)算 ( ∑ 0 < d < p d ? 1 ) m (\sum_{0

思路:

本題是一個(gè)小思維題,對(duì)于一個(gè)素?cái)?shù) p p p 來(lái)說(shuō), p p p 的剩余系的每個(gè)元素的逆仍然構(gòu)成它的剩余系。我們記 p p p 的剩余系是 P P P ,對(duì)于 a ∈ P a \in P a∈P 來(lái)說(shuō), a a a 的逆一共有兩種情況,第一種情況是 a ? 1 = a a^{-1}=a a?1=a,第二種情況是 a ? 1 = b , b ∈ P a^{-1}=b,b\in P a?1=b,b∈P,此時(shí) b ? 1 = a b^{-1}=a b?1=a,所以總體來(lái)說(shuō)取逆并不會(huì)有什么變化,括號(hào)里面本質(zhì)上就是一個(gè)等差數(shù)列求和。注意數(shù)據(jù)范圍, p p p 會(huì)很大,所以 p ? ( p ? 1 ) p*(p-1) p?(p?1) 時(shí)會(huì)爆 l o n g l o n g longlong longlong,所以要先取模 998244353 998244353 998244353,除以 2 2 2 轉(zhuǎn)化成乘 2 2 2 的逆元,之后做一遍快速冪就可以了。

#include#include#include#include#include#include#include#include
#include#includeusing namespace std;
#define ll long long
const ll N = 1e5+5;
const ll mod = 998244353;

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

int main()
{std::ios::sync_with_stdio(false);
    ll p, m;
    cin >>p >>m;
    p %= mod;
    ll ans = (p * (p-1) % mod) * qpow(2, mod-2) % mod;
    cout<< qpow(ans, m)<< '\n';
	return 0;
}
Problem B 收收心找個(gè)電子廠上班了【區(qū)間貪心/差分約束】

出題人: LYJ

很可惜,賽時(shí)并沒有人過這個(gè)題

題目描述:

給你m種條件(l[i],r[i],c[i]),要求構(gòu)造一個(gè)01串,使得l[i]r[i]中至少有c[i]個(gè)1,問滿足所有條件下1的數(shù)量最少的串是什么

思路1

經(jīng)典的區(qū)間貪心問題,我們將m種條件按照r從大到小排序

對(duì)于一個(gè)區(qū)間[l,r],我們先計(jì)算一下區(qū)間中已經(jīng)存在了多少個(gè)1,剩下的1就選最靠近r的那幾個(gè)不是1的位置。

所以我們需要一個(gè)數(shù)據(jù)結(jié)構(gòu)維護(hù)一下區(qū)間查詢/更新 1的數(shù)量,還需要一個(gè)數(shù)據(jù)結(jié)構(gòu)可以知道當(dāng)前這個(gè)位置往前的一個(gè)不是1的位置,來(lái)進(jìn)行更新

我們可以用樹狀數(shù)組或者線段樹進(jìn)行區(qū)間的維護(hù)

利用并查集進(jìn)行維護(hù)i往前的第一個(gè)不為1的位置

#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define No cout<<"No\n"
#define Yes cout<<"Yes\n"
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define lowbit(x) (x&(-x))
#define io ios::sync_with_stdio(false)
typedef long long ll;
typedef pairpii;

#define MAX 300000 + 50
int n, m, k, x, y, p;
struct ran{int l, r, x;
    int id;
    bool operator< (const ran &a)const{return r< a.r;
    }
}tr[MAX];

int ans[MAX];
int fa[MAX];
int getfa(int x){return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}

int ar[MAX];
void add(int id){while(id<= n){++ar[id];
        id += lowbit(id);
    }
}
int getans(int id){int ans = 0;
    while(id){ans += ar[id];
        id -= lowbit(id);
    }
    return ans;
}

void work(){cin >>n >>m;
    for(int i = 1; i<= m; ++i){cin >>tr[i].l >>tr[i].r >>tr[i].x;
        tr[i].id = i;
    }
    sort(tr+1, tr+1+m);
    for(int i = 1; i<= n; ++i)fa[i] = i;
    for(int i = 1; i<= m; ++i){tr[i].x -= (getans(tr[i].r) - getans(tr[i].l - 1));
        if(tr[i].x<= 0)continue;
        for(int id = getfa(tr[i].r); tr[i].x;id = getfa(id)){add(id);
            --tr[i].x;
            fa[id] = getfa(id-1);
            ans[id] = 1;
        }
    }
    for(int i = 1; i<= n; ++i)cout<< ans[i]<< " \n"[i==n];
}


int main(){io;
    work();
    return 0;
}
思路2:

差分約束板子題

假設(shè)所求數(shù)組叫做ar[i]

則我們令sum[i]表示ar數(shù)組的前綴和數(shù)組,對(duì)于l, r, c我們可以轉(zhuǎn)換成sum[r]-sum[l-1] >= c,因?yàn)榍蟮氖亲钚≈?,所以跑最長(zhǎng)路,用>號(hào),也就是sum[r] >= sum[l-1] + c,建一條l-1r的權(quán)值為c的邊,但是為了避免使用0,我們改成lr+1建一條邊

因?yàn)槭乔熬Y和,且一個(gè)位置最多一個(gè)1,所以建立一個(gè)0≤sum[i]-sum[i-1]≤1的條件,拆開來(lái)看就是sum[i]≥sum[i-1]+0,建一條從i-1i的權(quán)值為0的邊,sum[i-1]≥sum[i]-1,建立一條從ii-1的權(quán)值為-1的邊,因?yàn)榇嬖谪?fù)權(quán)邊,所以跑SPFA

得到的前綴和數(shù)組再做一次差分就可以得到原數(shù)組

#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 998244353
#define No cout<<"No\n"
#define Yes cout<<"Yes\n"
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false)
typedef long long ll;
typedef pairpii;

#define MAX 1000000 + 50
int n, m, k, l, r, c, p;

int tot;
int head[MAX];
struct ran{int to, nex, val;
}tr[MAX];
inline void add(int u, int v, int c){tr[++tot].to = v;
    tr[tot].val = c;
    tr[tot].nex = head[u];
    head[u] = tot;
}

int dis[MAX];
bool vis[MAX];
void spfa(){dequeq;
    for(int i = 1; i<= n; ++i){q.push_back(i);
        dis[i] = 0;
        vis[i] = 1;
    }
    while (!q.empty()) {int u = q.front();q.pop_front();vis[u] = 0;
        for(int i = head[u]; i; i = tr[i].nex){int v = tr[i].to;
            if(dis[v]< dis[u] + tr[i].val){dis[v] = dis[u] + tr[i].val;
                if(!vis[v]){vis[v] = 1;
                    if(!q.empty() && dis[q.front()] >dis[v])q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
    for(int i = 2; i<= n + 1; ++i){cout<< dis[i] - dis[i - 1]<< " \n"[i==n+1];
    }
}


void work(){cin >>n >>m;
    for(int i = 1; i<= n; ++i){add(i, i+1, 0);
        add(i+1, i, -1);
    }
    for(int i = 1; i<= m; ++i){cin >>l >>r >>c;
        add(l, r+1, c);
    }
    spfa();
}


int main(){io;
    work();
    return 0;
}
Problem C 我沒有腦子【打表/矩陣快速冪】

出題人: JBQ

很遺憾這么簽到的一道題沒有人做

題目描述:

生兔子,兔子的數(shù)量是斐波那契數(shù)列

問第l億年到第r億年出生了多少兔子,且出生的兔子并不包括第l年出生的兔子,第0年是沒有兔子出生的

思路:

觀察一下數(shù)據(jù)范圍,會(huì)發(fā)現(xiàn)0<=l,r<=300,顯然是個(gè)簡(jiǎn)單的打表題,我們可以暴力跑斐波那契求出0億到300億的斐波那契數(shù),跑的時(shí)候可以用三個(gè)變量來(lái)回倒換即可避免數(shù)組開不下的問題,大概本地跑個(gè)幾分鐘就能打出表,然后用數(shù)組記錄下來(lái)第i億年的斐波那契數(shù),這就是一個(gè)前綴和,查詢哪個(gè)區(qū)間就利用前綴和的性質(zhì)計(jì)算一下就行

因?yàn)樯婕暗綔p法,所以會(huì)出現(xiàn)負(fù)數(shù)的情況,記得+mod后再對(duì)mod取模

當(dāng)然,這是一個(gè)矩陣快速冪的板子題,套了就能過

#includeusing namespace std;
typedef long long ll;
const double pi = acos(-1);
const ll mod = 998244353;

ll qz[] = {0,798940737,702476549,882271746,158813243,717203476,338005251,116925432,142361015,915249973,857532739,753217439,520526462,729616988,647870145,371082495,841434648,373792903,192185450,309635100,846033167,574139965,802208229,788931688,653823084,498623881,381227773,444199493,541776490,385469308,204954591,661354559,261075692,24044029,83866001,584279557,45051147,173356045,821097718,163787363,787428576,988607439,538194736,477301409,856030254,182481274,696848072,333236726,460460936,413870920,87699598,677867260,933901576,122519290,433328905,517328471,66133697,748952995,271526780,951814203,603251788,538205993,786735739,210759723,471369471,844152090,451425750,64320864,664523635,755126352,322282207,848963789,601663281,955920251,188264055,448820184,924870015,870684039,690825122,363991368,510949049,787514543,868353515,23576757,729097988,456367806,120642843,745912349,311624691,396321784,468768789,940449311,479622530,706285186,96018834,614222128,531387322,51266835,824627665,26443258,661596038,328505115,470346561,301752734,536314862,51032382,156416715,858226445,377889809,802029259,44891519,618514642,28412917,845529642,248409413,138438148,983915659,347993720,721251618,402015592,208058847,859078897,523989448,504052355,248065071,501719314,706051327,634108576,257642722,164709287,863618638,306954392,910875941,655103461,467141818,572508067,664175525,947444075,469933222,883991102,757741015,1474536,709356522,802778892,578012184,112096396,37994672,704609404,18735451,258157019,554151314,327440787,420681318,119115175,114348722,45849809,854152074,660727321,437865313,839664896,833951917,574989040,378592331,262142690,699881570,924047133,283460224,695823769,961649873,956270153,66045054,288527356,116809227,330703987,815531292,536702953,963616030,172058590,361328034,404667451,335937034,608229080,406337321,288852773,916154288,405321356,248562231,772003667,344018140,279265806,721778550,617440080,379179999,472866396,426600720,144286727,723894575,399751987,354317264,540289590,440230859,846662817,864857587,718655634,950096265,290426201,791678815,231978197,160685153,385229934,71853234,451895282,34336651,939727748,451455552,731675730,291527149,485355441,340321224,978564745,683403470,256607555,459702481,754509303,983134135,547374590,123507260,123212517,907699376,880893030,380044243,404686542,919434049,296606692,738071182,474476191,947772155,54578357,312799315,66989458,797607101,925860402,205607764,532696276,90867276,936962661,877887130,864602607,245414428,760338293,213637659,193249572,807595867,285884919,259032359,770485780,361717598,182833844,813779029,873553462,356707666,208580125,718898155,707280088,309609449,162174566,648557431,919420983,940109378,631849990,799994020,679817491,929829530,453450192,264396037,431709960,795394812,17661181,677218455,695586920,475003070,543790903,220685197,455960728,932178450,803872141,700865964,215343465,176830374,118069191,353690631,564849453,512987043,169310973,857323540,761677403,906282770,943136960,292380651,93349738,29943185};

int main()
{ll T,p,q;
	cin>>T;
	while(T--){cin>>p>>q;
		cout<<(qz[q] - qz[p] + mod)%mod<
#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 998244353
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef pairpii;

#define MAX 300000 + 50
int n, m, k, x, y;
int tr[MAX];

struct Matrix{ll tr[2][2];
    Matrix(){mem(tr, 0);
    }
    Matrix operator * (const Matrix y){Matrix ans;
        for(int i = 0; i< 2; ++i){for(int j = 0; j< 2; ++j){for(int k = 0; k< 2; ++k){(ans.tr[i][j] += tr[i][k] * y.tr[k][j]) %= mod7;
                }
            }
        }
        return ans;
    }
    void operator = (const Matrix b){for(int i = 0; i< 2; ++i){for(int j = 0; j< 2; ++j){tr[i][j] = b.tr[i][j];
            }
        }
    }
};
ll getans(ll n){Matrix ans, cnt;
    ans.tr[0][0] = ans.tr[1][1] = 1;
    cnt.tr[0][0] = cnt.tr[0][1] = cnt.tr[1][0] = 1;
    while(n){if(n & 1)ans = ans * cnt;
        cnt = cnt * cnt;
        n /= 2;
    }
    return ans.tr[0][0];
}

ll fuck[MAX];

void work(){for(ll i = 1; i<= 300; ++i){fuck[i] = getans(i * 100000000ll - 1);
    }
    int t;cin>>t;
    while(t--){cin >>x >>y;
        cout<< (fuck[y] - fuck[x] + mod7) % mod7<< endl;
    }
}


int main(){io;
    work();
    return 0;
}
Problem D 我是殺豬飼料,祝你天天開心【簽到】

出題人: LYJ

本來(lái)沒想出hello world的題,但是突然接到通知大二不打了,這套題只給大一打,我就連夜加了一道

如果沒有這個(gè)題,大家很可能五個(gè)小時(shí)都在牢底坐穿

還是要祝一下蛇姐生日快樂耶!

題目描述:

輸出”蛇姐生日快樂!!!”即可

#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef pairpii;

#define MAX 300000 + 50
int n, m, k, x;
int tr[MAX];

void work(){cout<< "蛇姐生日快樂!!!";
}

int main(){io;
    work();
    return 0;
}
Problem E 沒什么特殊意義,就是想混一個(gè)最長(zhǎng)的題目名字,然后讓大家點(diǎn)進(jìn)來(lái)做這道題

出題人: NXY

關(guān)于xygg出了個(gè)權(quán)值線段樹卻被兩個(gè)人用別的思路隨便卡過去這件事

思路:

第一種做法:離散化 + 權(quán)值線段樹
我們發(fā)現(xiàn)每個(gè)數(shù)本身沒有什么用,我們需要的僅僅是他們之間的大小關(guān)系,而 N N N 又不是很大,所以考慮離散化。
然后把離散化之后的序列用權(quán)值線段樹維護(hù)起來(lái)。

第二種做法:平衡樹
動(dòng)態(tài)查詢第 k k k 大數(shù),容易想到平衡樹直接維護(hù)

第三種做法:對(duì)頂堆
szz \texttt{szz} szz 的考場(chǎng)做法。

第四種做法: 主席樹
gts \texttt{gts} gts 的考場(chǎng)做法

大家如果要補(bǔ)題的話建議學(xué)習(xí)第一種做法和第三種做法,第一種做法很典型很常見,是一種必不可少的技能點(diǎn)。第三種做法思維上很巧妙很有意思,并且代碼簡(jiǎn)短容易理解,也同樣建議大家學(xué)習(xí)

#includeusing namespace std;
const int N = 1e5 + 10;

int n,w;
int a[N],b[N],c[N];

bool cmp(int x , int y)
{return x >y;}

struct NO
{int l;
    int r;
    int w;
};

struct SigmentT
{NO t[N * 4];
    void Build(int p , int l , int r)
    {t[p].l = l; t[p].r = r;
        if(l == r) return;
        int mid = (l + r) >>1;
        Build(p<< 1 , l , mid);
        Build(p<< 1 | 1 , mid + 1 , r);
    }

    void Updata(int p , int w)
    {if(t[p].l == t[p].r) {t[p].w++; return;
        }
        int mid = (t[p].l + t[p].r) >>1;
        if(w<= mid) Updata(p<< 1 , w);
        else Updata(p<< 1 | 1 , w);
        t[p].w = t[p<< 1].w + t[p<< 1 | 1].w;
    }

    int Query(int p , int k)
    {if(t[p].l == t[p].r) return t[p].l;
        if(t[p<< 1].w< k) return Query(p<< 1 | 1, k - t[p<< 1].w);
        else return Query(p<< 1 , k);
    }
}tr;

int main()
{//freopen("aa.in","r",stdin);
    scanf("%d%d",&n,&w); 
    for(int i = 1; i<= n; i++)
        scanf("%d",&a[i]) , b[i] = a[i];

    std::sort(b + 1 , b + 1 + n);
    int LEN = std::unique(b + 1 , b + 1 + n) - b - 1;
    for(int i = 1, tmp; i<= n; i++)
        tmp = a[i] , a[i] = std::lower_bound(b + 1 , b + 1 + LEN , a[i]) - b , c[a[i]] = tmp;
    
    tr.Build(1 , 0 , LEN);
    for(int i = 1; i<= n; i++)
    {int m = max(1 , i * w / 100);
        tr.Updata(1 , a[i]);
        printf("%d ",c[tr.Query(1 , i - m + 1)]);
    }
    
}
#includeconst int N = 3e5 + 10;

int n,w;
int a[N];

struct No {int p,siz,val,sel,son[2];
};

struct SBT{int rt,idx;
    No t[N];

    void Pushup(int u) {t[u].siz = t[t[u].son[0]].siz + t[t[u].son[1]].siz + t[u].sel;
    }

    void rotate(int u) {int y = t[u].p , z = t[y].p;
        int k = t[y].son[1] == u;
        t[z].son[t[z].son[1] == y] = u , t[u].p = z;
        t[y].son[k] = t[u].son[k ^ 1] , t[t[u].son[k ^ 1]].p = y;
        t[u].son[k ^ 1] = y , t[y].p = u;
        Pushup(y) , Pushup(u);
    }

    void Splay(int u , int p) {while(t[u].p != p) {int y = t[u].p , z = t[y].p;
            if(z != p)
                if((t[z].son[1] == y) ^ (t[y].son[1] == u))
                    rotate(u);
                else rotate(y);
            rotate(u);
        }
        if(!p) rt = u;
    }

    void insert(int val) {int u = rt , p = 0;
        while(u) {if(val == t[u].val) break;
            p = u , u = t[u].son[val >t[u].val];
        }
        if(!u) u = ++idx;
        t[u].sel++;t[u].p = p;t[u].val = val;
        if(p) t[p].son[val >t[p].val] = u;
        Splay(u , 0);
    }

    int getk(int k) {int u = rt;
        while(1) {if(k<= t[t[u].son[0]].siz) u = t[u].son[0];
            else if(k<= t[t[u].son[0]].siz + t[u].sel) {Splay(u , 0); return t[u].val;
            }
            else k -= t[t[u].son[0]].siz + t[u].sel , u = t[u].son[1];
        }
    }
}tr;

const int inf = 1e9;

int main() {//freopen("aa.in","r",stdin);
    scanf("%d%d",&n,&w); tr.insert(-1) , tr.insert(inf);
    for(int i = 1 , x; i<= n; i++) {scanf("%d",&x); tr.insert(x);
        int end = std::max(1 , i * w / 100);
        printf("%d ",tr.getk(i - end + 1 + 1));
    }
}
Problem F 瀧1千0(hard version)【構(gòu)造】

出題人: DJK

看hard版之前先看看easy版的

題目描述:

跟簡(jiǎn)單版相比,不同點(diǎn)在于字符串長(zhǎng)度,和操作總次數(shù)發(fā)生了變化。

思路:

給出其中一種構(gòu)造方式。

由于是對(duì)前綴進(jìn)行操作,容易想到從后向前匹配兩個(gè)01串,當(dāng) s 串 與 t 串 s串與t串 s串與t串在位置 i i i不同時(shí),執(zhí)行操作 i i i,但當(dāng)執(zhí)行完操作 i i i后, s 串 和 t 串 s串和t串 s串和t串在位置 i i i依舊可能不匹配,所以我們需要預(yù)處理 s s s串,讓它全變成 0 0 0或 1 1 1,這樣的話就可以保證執(zhí)行操作 i i i后,一定匹配。

容易發(fā)現(xiàn),至多操作 2 ? n 2*n 2?n次(預(yù)處理至多 n n n次,從后向前匹配過程至多 n n n次)。

#includeusing namespace std;
typedef long long ll;
//#define int ll
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
#define pii pairconst int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double eps = 1e-4;
int n, sum;
string s1, s2;
char ch;
int ans[maxn];

int main()
{io;
    //freopen("20.in", "r", stdin);
    //freopen("20.out", "w", stdout);
    cin >>s1 >>s2;
    n = s1.size();
    s1 = '$' + s1;
    s2 = '$' + s2;
    sum = 0;
    for(int i = 2; i<= n; ++i)
    {if(s1[i] != s1[i - 1])
            ans[++sum] = i - 1;
    }
    ch = s1[n] - '0';
    for(int i = n; i >0; --i)
    {if(ch != (s2[i] - '0'))
        {ans[++sum] = i;
            ch = 1 - ch;
        }
    }
    cout<< sum;
    for(int i = 1; i<= sum; ++i) cout<< ' '<< ans[i];
    cout<< '\n';
    return 0;
}
Problem G A+B Problem【ull自然溢出】

出題人:NXY

a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊a+b啊

這個(gè)題最開始的時(shí)候是NXY想考ull自然溢出等于對(duì)264取模,所以題目名稱本來(lái)叫做**“自然溢出啥事沒有!”**,但是有狗提議改把a(bǔ)和b的數(shù)字的長(zhǎng)度改到1e5,使得NXY卡了一下py(

思路:

需要用到的知識(shí)點(diǎn)有兩個(gè):

  • unsigned long long自然溢出等價(jià)于對(duì) 2 64 2^{64} 264 取模,也就是說(shuō)自然溢出啥事沒有!
  • ( a × b + c ) ? % ? p = ( ( a × b ) ? % ? p + c ? % ? p ) ? % ? p (a\times b + c)\ \%\ p = ((a\times b)\ \%\ p+c\ \%\ p)\ \%\ p (a×b+c)?%?p=((a×b)?%?p+c?%?p)?%?p

因此我們只需要把輸入的數(shù) a a a 分解為 a = x ? 10 + c a = x * 10 + c a=x?10+c即可

NXY 特意卡了 python

#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef unsigned long long ull;
typedef pairpii;

#define MAX 300000 + 50
string s;
ull a, b;

void work(){cin >>s;
    a = b = 0;
    for(auto x : s){a = a * 10 + (ull)(x - '0');
    }
    cin >>s;
    for(auto x : s){b = b * 10 + (ull)(x - '0');
    }
    cout<< (ull)(a+b)<io;
    work();
    return 0;
}
Problem H 柳予欣的色圖【Pólya 計(jì)數(shù)】

出題人: BHQ

防AK題

題目描述:

一個(gè)手鏈上有 n n n 個(gè)珠子,有 n n n 種顏色,給每個(gè)珠子都染上顏色。有多少種不同的染色方法。由于方案數(shù)很多,請(qǐng)對(duì) 998244353 998244353 998244353 取模。

題解

Pólya 計(jì)數(shù)的裸題,很難,想了解可以自己了解。

#include#include#include#include#include#include#include#include
#include#includeusing namespace std;
#define ll long long
const int N = 1e4+5;
const ll mod = 998244353;

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

ll phi(ll n){ll ans = n;
    for(int i = 2; i*i<= n; ++i){if(n % i == 0){ans = ans / i * (i-1);
            while(n % i == 0)
                n /= i;
        }
    }
    if(n != 1)
        ans = ans / n * (n-1);
    return ans;
}

void solve(ll n){if(n == 1)
        cout<< 1<< '\n';
    else
    {ll ans = 0;
        for(int i = 1; i * i<= n; ++i){if(n % i == 0){if(i * i == n)
                    ans = (ans + (phi(n/i) * qpow(n, i, mod) % mod)) % mod;
                else{ans = (ans + (phi(i) * qpow(n, n/i, mod) % mod)) % mod;
                    ans = (ans + (phi(n/i) * qpow(n, i, mod) % mod)) % mod;
                }
            }
        }
        cout<< (ans * qpow(n, mod-2, mod)) % mod<< '\n';
    }
}

int main()
{std::ios::sync_with_stdio(false);
    ll n;
    cin >>n;
    solve(n);
	return 0;
}
Problem I WWW的雜貨鋪【模擬】

出題人: WYY

題目描述:

M條出售記錄,每條出售記錄由物品名稱、收貨地、出售數(shù)目組成。

請(qǐng)按如下規(guī)則進(jìn)行統(tǒng)計(jì)并輸出:物品按收貨地分類,并合并出售數(shù)目,收貨地按字典序排列,同一收貨地的物品按字典序排列。

思路:

很簡(jiǎn)單的模擬題,沒什么意思

#pragma GCC optimize(3)
#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef pairpii;

#define MAX 300000 + 50
int n, m, k, op;
int x, y, z;
string s, t;

struct ran{string s;
    mapmp;
}tr[105];

void work(){cin >>n;
    for(int i = 1; i<= 100;++i)tr[i].mp.clear();
    mapmp;
    int tot = 0;
    for(int i = 1; i<= n; ++i){cin >>s >>t >>x;
        if(!mp.count(t))mp[t] = ++tot;
        tr[mp[t]].s = t;
        tr[mp[t]].mp[s]+=x;
    }
    for(auto [x,y] : mp){cout<< tr[y].s<< endl;
        cout<< "--------------------\n";
        for(auto [u, v] : tr[y].mp){cout<< "    ";
            cout<< u<< "("<io;
    int tt;cin>>tt;
    for(int _t = 1; _t<= tt; ++_t){work();
        if(_t != tt)cout<< endl;
    }
    return 0;
}
Problem J 去玩寶可夢(mèng)嘍~ 【dp+線段樹】

出題人: DJK

題目描述:

脫離題干背景,單純考慮區(qū)間操作,發(fā)現(xiàn)題意如下:

給你一個(gè)長(zhǎng)度為 n ( 1 ≤ n ≤ 5 ? 1 0 5 ) n(1≤n≤5*10^5) n(1≤n≤5?105)的數(shù)組。你需要將其分成幾段連續(xù)的子區(qū)間,每一段區(qū)間的權(quán)值如下:

  • 若區(qū)間和大于0,則為區(qū)間長(zhǎng)度
  • 如區(qū)間和等于0,則為0
  • 如區(qū)間和小于0,則為區(qū)間長(zhǎng)度的相反數(shù)

用一個(gè)式子表示即: v a l [ l , r ] = s i g n ( s u m [ l , r ] ) ? ( r ? l + 1 ) val[l,r] = sign(sum[l,r]) * (r - l + 1) val[l,r]=sign(sum[l,r])?(r?l+1) ( v a l [ l , r ] 表 示 區(qū) 間 [ l , r ] 的 權(quán) 值 , s i g n 函 數(shù) 同 原 題 中 的 f 函 數(shù) , s u m [ l , r ] 亦 相 同 ) (val[l,r]表示區(qū)間[l,r]的權(quán)值,sign函數(shù)同原題中的f函數(shù),sum[l,r]亦相同) (val[l,r]表示區(qū)間[l,r]的權(quán)值,sign函數(shù)同原題中的f函數(shù),sum[l,r]亦相同)

問你分出來(lái)的子區(qū)間的權(quán)值和大為多少,并且是否大于等于 H H H。

思路

數(shù)據(jù)結(jié)構(gòu)優(yōu)化DP

我們首先考慮暴力解法。

定義 d p [ i ] dp[i] dp[i]為 [ 1 , i ] [1,i] [1,i]中的大權(quán)值和,容易發(fā)現(xiàn)可以 O ( n ) O(n) O(n)轉(zhuǎn)移,總體復(fù)雜度需要 O ( n 2 ) O(n^2) O(n2)。

轉(zhuǎn)移方程: d p [ i ] = m a x ( d p [ i ] , d p [ j ] + s i g n ( s u m [ j + 1 , i ] ) ? ( i ? ( j + 1 ) + 1 ) ) 其 中 ( 0 ≤ j < i ) dp[i] = max(dp[i], dp[j] + sign(sum[j+1,i]) * (i-(j+1)+1)) 其中(0≤j

復(fù)雜度過高,我們考慮優(yōu)化。

根據(jù) s i g n sign sign函數(shù)的值分類討論,化簡(jiǎn)轉(zhuǎn)移方程:

d p [ i ] = m a x ( d p [ i ] , d p [ j ] + s i g n ( s u m [ i ] ? s u m [ j ] ) ? ( i ? j ) ) dp[i] = max(dp[i],dp[j]+sign(sum[i]-sum[j])*(i-j)) dp[i]=max(dp[i],dp[j]+sign(sum[i]?sum[j])?(i?j))

若 s u m [ i ] = = s u m [ j ] sum[i]==sum[j] sum[i]==sum[j], d p [ i ] = m a x ( d p [ j ] ) dp[i] = max(dp[j]) dp[i]=max(dp[j])

若 s u m [ i ] > s u m [ j ] sum[i] >sum[j] sum[i]>sum[j], d p [ i ] = m a x ( d p [ j ] ? j + i ) dp[i] = max(dp[j] - j +i) dp[i]=max(dp[j]?j+i)

若 s u m [ i ] < s u m [ j ] sum[i]< sum[j] sum[i]

我們只需要求出上述三種情況下對(duì)應(yīng)的 m a x max max,之后這三個(gè)值取 m a x max max即可。

容易發(fā)現(xiàn),需要一個(gè)支持單點(diǎn)修改+區(qū)間查詢且復(fù)雜度過得去的數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)。

做法是預(yù)處理前綴和,之后離散化,然后按照前綴和建線段樹(其他滿足條件的數(shù)據(jù)結(jié)構(gòu)均可)。

即線段樹的下標(biāo)表示 s u m [ j ] sum[j] sum[j],上述的三個(gè)大值分別通 q u e r y ( s u m [ i ] , s u m [ i ] ) query(sum[i],sum[i]) query(sum[i],sum[i]), q u e r y ( 1 , s u m [ i ] ? 1 ) query(1, sum[i]-1) query(1,sum[i]?1), q u e r y ( s u m [ i ] + 1 , n ) query(sum[i] + 1, n) query(sum[i]+1,n)獲得。

復(fù)雜度 O ( n l o g n ) O(nlogn) O(nlogn)。

另外,提示中試試暴力是希望先寫出暴力轉(zhuǎn)移方程,方便之后的觀察優(yōu)化。

5 e 5 5e5 5e5的數(shù)據(jù)量暴力是不可能過的。

下面給出利用線段樹優(yōu)化的代碼。

#includeusing namespace std;
typedef long long ll;
#define int ll
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
#define itt set::iterator
#define pii pairconst int inf = 0x3f3f3f3f;
const int maxn = 5e5 + 5;
int t, n, x, h;
int sum[maxn];
int dp[maxn];
vectorvt;
struct node
{int l, r;
    int dp, dp1, dp2;//維護(hù)上述的三個(gè)大值

    int mid()
    {return (l + r) >>1;
    }

    void print()
    {cout<< l<< ' '<< r<< ' '<< dp<< ' '<< dp1<< ' '<< dp2<< '\n';
    }
} tree[maxn<<2];

void pushup(node &p, node &le, node &ri)
{p.l = le.l;
    p.r = ri.r;
    p.dp = max(le.dp, ri.dp);
    p.dp1 = max(le.dp1, ri.dp1);
    p.dp2 = max(le.dp2, ri.dp2);
}

void pushup(int p)
{pushup(tree[p], tree[p<<1], tree[p<<1|1]);
}

void build(int p, int l, int r)
{tree[p].l = l;
    tree[p].r = r;

    if(l == r)
    {tree[p].dp = tree[p].dp1 = tree[p].dp2 = -inf;
        return ;
    }

    int mid = tree[p].mid();
    build(p<<1, l, mid);
    build(p<<1|1, mid + 1, r);
    pushup(p);
}

void updata(int p, int pos, int dp, int id)
{if(tree[p].l == tree[p].r)
    {tree[p].dp = max(tree[p].dp, dp);
        tree[p].dp1 = max(tree[p].dp1, dp - id);
        tree[p].dp2 = max(tree[p].dp2, dp + id);
        return ;
    }

    int mid = tree[p].mid();
    if(pos<= mid) updata(p<<1, pos, dp, id);
    else updata(p<<1|1, pos, dp, id);
    pushup(p);
}

node query(int p, int l, int r)
{if(l >r) return {-inf, -inf, -inf, -inf};
    if(l<= tree[p].l && tree[p].r<= r) return tree[p];

    int mid = tree[p].mid();
    if(mid >= r) return query(p<<1, l, r);
    else if(mid< l) return query(p<<1|1, l, r);
    else
    {node le = query(p<<1, l, r);
        node ri = query(p<<1|1, l, r);
        node res;
        pushup(res, le, ri);
        return res;
    }
}

void work()
{vt.clear();
    cin >>n >>h;
    for(int i = 1; i<= n; ++i)
    {cin >>x;
        sum[i] = sum[i - 1] + x;
        vt.push_back(sum[i]);
        dp[i] = 0;
    }
    vt.push_back(0);

    sort(vt.begin(), vt.end());
    vt.erase(unique(vt.begin(), vt.end()), vt.end());

    build(1, 1, vt.size());

    node pp;
    int mx1, mx2, mx3, pos;
    pos = lower_bound(vt.begin(), vt.end(), 0) - vt.begin() + 1;
    updata(1, pos, 0, 0);
    for(int i = 1; i<= n; ++i)
    {pos = lower_bound(vt.begin(), vt.end(), sum[i]) - vt.begin() + 1;
        mx1 = query(1, 1, pos - 1).dp1;
        mx2 = query(1, pos, pos).dp;
        mx3 = query(1, pos + 1, vt.size()).dp2;
        dp[i] = max(mx1 + i, max(mx2, mx3 - i));
        updata(1, pos, dp[i], i);
    }

    cout<< dp[n]<< ' '<< (dp[n] >= h)<< '\n';
}

signed main()
{io;
    cin >>t;
    while(t--) work();
    return 0;
}
Problem K 逃出虛圈!【bfs】

出題人: LYJ

出了一個(gè)bfs的模版題,沒人做,好傷心,寫了半天的題目背景,沒人看,好傷心,甚至在賽時(shí)加了一個(gè)小彩蛋,也沒人看,好傷心

雖然

題目描述:

n個(gè)點(diǎn),m條邊,無(wú)向圖

給你p個(gè)起點(diǎn),q個(gè)終點(diǎn),問你從任意一個(gè)起點(diǎn)出發(fā),到達(dá)任意一個(gè)終點(diǎn)需要的最短距離是多少

思路:

bfs就行,把起點(diǎn)都塞進(jìn)隊(duì)列里面,然后記錄q個(gè)終點(diǎn),跑的時(shí)候遇到第一個(gè)出現(xiàn)的終點(diǎn)的時(shí)候就是最短的

#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef pairpii;

#define MAX 1000000 + 50
int n, m, k, x, y, a, b;
vectorG[MAX];

queueq;
setse;
int dis[MAX];

void bfs(){while(!q.empty()){int u = q.front();q.pop();
        if(se.count(u)){cout<< dis[u]<< endl;
            return;
        }
        for(auto v : G[u]){if(dis[v] != inf)continue;
            dis[v] = dis[u] + 1;
            q.push(v);
        }
    }
    cout<< "N0"<< endl;
}

void work(){cin >>n >>m;
    for(int i = 1; i<= m; ++i){cin >>x >>y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    mem(dis, inf);
    cin >>a >>b;
    for(int i = 1; i<= a; ++i){cin >>x;
        q.push(x);
        dis[x] = 0;
    }
    for(int i = 1; i<= b; ++i){cin >>x;
        se.insert(x);
    }
    bfs();
    
}

int main(){work();
    return 0;
}
Problem L 為愛發(fā)電的Oier【簡(jiǎn)單期望】

出題人: WWY

簽到題,沒人寫,6

題目描述:

我們可以把題目理解成拋硬幣,問期望拋多少次可以使得正面朝上的次數(shù)是n

思路:

顯然,期望拋2次,可以使得正面朝上的次數(shù)是1

拿n次正面朝上的期望就是2*n

所以輸出2*n就行

這里有一個(gè)很有意思的事情:

image-20221204200818664

十六分鐘的時(shí)候就有人看到了這個(gè)題,并寫出了正解,但是因?yàn)樗麤]寫輸入,所以掛了,(笑死

#pragma GCC optimize(3)
#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
typedef pairpii;

#define MAX 300000 + 50
int n, m, k, x;
int tr[MAX];

void work(){cin >>n;
    cout<< 2 * n<< endl;
}


int main(){io;
    work();
    return 0;
}
Problem M完全不管大一死活【分類討論】

出題人: LYJ

出題的時(shí)候,在這個(gè)題前面出了五六個(gè)題,沒有一個(gè)簽到題,所以我就放了一個(gè)小討論題

題目描述:

你在0的位置,目標(biāo)是x的位置,y的位置有一個(gè)門,z的位置有一個(gè)鑰匙,問你最少需要走幾步能到x,如果不能到輸出-1

思路:

簽到題,簡(jiǎn)單分類一下就行,沒什么意思

#includeusing namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false)
#define debug(a) cout<< "Debuging...|"<< #a<< ": "<< a<< "\n";
typedef long long ll;
typedef pairpii;

#define MAX 300000 + 50
int x, y, z;

void work(){cin >>x >>y >>z;
    if(x == 0){cout<< 0<< endl;
    }
    else if(x >0){if(y< 0 || y >x)cout<< x<< endl;
        else {if(z >y)cout<< "BLEACH yyds"<< endl;
            else{if(z >0)cout<< x<< endl;
                else cout<< -z*2 + x<< endl;
            }
        }
    }
    else{if(y< x || y >0)cout<< -x<< endl;
        else{if(z< y)cout<< "BLEACH yyds"<< endl;
            else {if(z >0)cout<< 2*z - x<< endl;
                else cout<< -x<< endl;
            }
        }
    }
}


int main(){io;
    work();
    return 0;
}
Problem N 瀧1千0(easy version)【構(gòu)造】

出題人: DJK

題目描述:

給你兩個(gè)字符串 s , t s,t s,t,按照給定的操作方式,是 s s s串變成 t t t串,要求在 3 ? n 3*n 3?n次內(nèi)完成( n n n是字符串的長(zhǎng)度)。

思路:

給出其中一種構(gòu)造方式。

我們希望當(dāng) s 串 與 t 串 s串與t串 s串與t串在位置 i i i不同時(shí),我們希望取反第 i i i個(gè)元素且不影響其他元素,這樣就可以 O ( n ) O(n) O(n)遍歷一遍。

容易發(fā)現(xiàn),取反和反轉(zhuǎn)都擁有一個(gè)特征。即對(duì)一個(gè)01串取反或反轉(zhuǎn)偶數(shù)次,字符串不變。

由此,我們即可實(shí)現(xiàn)取反第 i i i個(gè)位置,而不影響其他元素。

當(dāng) s 串 與 t 串 s串與t串 s串與t串在位置 i i i不同時(shí),進(jìn)行如下操作:

  • 執(zhí)行操作 i i i
  • 執(zhí)行操作 1 1 1
  • 執(zhí)行操作 i i i

可以發(fā)現(xiàn),至多需要 3 ? n 3*n 3?n次,滿足題意。

代碼:

#includeusing namespace std;
typedef long long ll;
#define int ll
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
#define itt set::iterator
#define pii pairconst int inf = 0x3f3f3f3f;
const int maxn = 5e5 + 5;
int n;
string s, t;
int ans[3005];
int sum;

signed main()
{io;
    cin >>s >>t;

    n = s.size();
    sum = 0;
    for(int i = 0; i< n; ++i)
    {if(s[i] != t[i])
        {ans[++sum] = i + 1;
            ans[++sum] = 1;
            ans[++sum] = i + 1;
        }
    }

    cout<< sum<< ' ';
    for(int i = 1; i<= sum; ++i) cout<< ans[i]<< ' ';
    return 0;
}
總結(jié)

從出題情況來(lái)說(shuō),很多簽到題沒人看,沒人做,線上比賽比線下比賽的相比,差距很大,有些同學(xué)線上比賽沒人監(jiān)督,就隨便寫兩三個(gè)題就跑去玩了,這樣很不好…

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

當(dāng)前名稱:2022SDNU-ACM結(jié)訓(xùn)賽題解-創(chuàng)新互聯(lián)
網(wǎng)址分享:http://bm7419.com/article30/gioso.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、營(yíng)銷型網(wǎng)站建設(shè)、做網(wǎng)站、標(biāo)簽優(yōu)化網(wǎng)站導(dǎo)航、全網(wǎng)營(yíng)銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)