{小社題解}
Rank
# CHAPTER 2
lemonilemon
Score: 400
1.
lemonilemon
Score: 400
1.
並沒有
# CHAPTER 2
lemonilemon
Score: 400
1.
lemonilemon
Score: 400
1.
Rank
# CHAPTER 2
lemonilemon
Score: 400
1.
🐟🔪
Score: 328
1.
Rank
# CHAPTER 2
🐑
Score: 269
3.
Score: 288
2.

{pA}
理論上他要是最簡單的(?
題目
給你一顆像是樹的東西
並給你他下面可以連幾條邊出去
問你總共會有多少邊
要加上沒有被連到的邊(空著的)
要判斷的是每個人他還能被連幾次
某個人想去連他的時候能不能連
subtask 1 10p
ai=0 所有人都連上了代表交換器的0
算 n+∑bi
O(N)
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int n, q;cin>>n>>q; int ans=0; for(int i=0; i<q; i++){ string r;cin>>r; int a, b, c;cin>>a>>b>>c; ans+=c+1; }cout<<ans; }
subtask 2 13p
bi=N 所有人都可以被 N 個人連上
不用擔心會有人連到不該連的 一定夠
對於每次連接 若接上交換器則答案加bi+1 否則加bi
O(N)
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int n, q;cin>>n>>q; int ans=0; for(int i=0; i<q; i++){ string r;cin>>r; int a, b, c;cin>>a>>b>>c; ans+=c; if(b==0) ans++; }cout<<ans; }
subtask 3 27p
我寫題解的時候甚至沒印象我出過這個
但你想的到O(N2) 的解法就可喇(?
AC
我覺得解蠻直觀的ㄅ
開一個陣列存每個人還能分給幾個人
每次有人連他就--
連成功之後按照給的數字更改連的人的剩餘
如果要去連上一個剩零配額的人就報錯誤訊息
這題N蠻大的可以開全域變數或vector避免SIG
O(N)
# PRESENTING CODE
AC CODE
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second vector<int> canc(5000007, 0); signed main(){ ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0); int n, q;cin>>n>>q; int ans=0; canc[0]=INT32_MAX; for(int i=0; i<q; i++) { string name;cin>>name; int a, b, c;cin>>a>>b>>c; if(canc[b]){ canc[a]=c; ans+=c; if(b==0) ans++; canc[b]--; }else{ cout<<name<<" wanna steal internet\n"; } } cout<<ans; }
{pB}
墜河了
題目
給你一串陣列
每次問你一段區間的XOR SUM
btw題敘我用chatGPT寫的 還好大家都看懂了吧
subtask 1 40p
N,Q≤1000
報搜就好
對每次query跑一個for xor在一起就是了
聽說這個subtask變成簽到了
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int n, q;cin>>n>>q; vector<int> li(n); for(int i=0; i<n; i++) cin>>li[i]; for(int i=0; i<q; i++){ int a, b;cin>>a>>b; int ans=0; for(int j=a; j<=b; j++){ ans^=li[j]; }cout<<ans<<'\n'; } }
AC
N,Q≤100000
本來沒有很想講
但賽中加了個提示
a^b^b=a
意思是一個東西被xor到兩次的話他會消失
所以我們就可以用前綴和的方法去寫ㄌ
對於每一項 紀錄從第一項xor過來的值
對於一個要查詢的[l, r]區間
就算prexor[r]^prexor[l-1]
需要的區間的每一個都被算到一次
不需要的都被算到零次或二次
# PRESENTING CODE
AC CODE
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int n, q;cin>>n>>q; vector<int> pre(n+1); for(int i=1; i<=n; i++){ int a;cin>>a; pre[i]=pre[i-1]^a; } for(int i=0; i<q; i++){ int a, b;cin>>a>>b; cout<<(pre[a]^pre[b+1])<<'\n'; } }
{pC}
對不起我是小丑
題目
如果你知道甚麼是拓撲排序的話(請參閱圖論[1])
你會發現這是用pq拓排加上找LCS的裸題
subtask 1 80p
pq拓撲排序複雜度為 O(N logN)
LCS的複雜度為O(N2)
你會發現會炸 壓LCS的方法因為真的有點難靠自己通靈
所以這個subtask就先給80p了
記得要確切決定要走到哪一個點的時候再紀錄拓排順序
# PRESENTING CODE
Code Transitions
#include <bits/stdc++.h> using namespace std; #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int n, m;cin>>n>>m; vector<int> ind(n, 0); vector<vector<int>> adj(n); for(int i=0; i<m; i++){ int a, b;cin>>a>>b; adj[a].pb(b); ind[b]++; } priority_queue<int, vector<int>, greater<int>> q; vector<int> seq; for(int i=0;i<n; i++){ if(ind[i]==0) {q.push(i);} } vector<int> taken(n, 0); while(!q.empty()){ int tmp=q.top();q.pop(); //cout<<tmp<<' '; if(!taken[tmp]){ seq.pb(tmp);taken[tmp]=1;} for(int x:adj[tmp]){ ind[x]--; if(ind[x]==0){ //seq.pb(x); q.push(x); //taken[x]=1; //cout<<x<<' '; } } } int n2, m2;cin>>n2>>m2; vector<int> ind2(n2, 0); vector<vector<int>> adj2(n2); for(int i=0; i<m2; i++){ int a, b;cin>>a>>b; adj2[a].pb(b); ind2[b]++; } priority_queue<int, vector<int>, greater<int>> q2; vector<int> seq2; for(int i=0;i<n; i++){ if(ind2[i]==0) {q2.push(i);} }vector<int> taken2(n2, 0); while(!q2.empty()){ int tmp=q2.top();q2.pop(); if(!taken2[tmp]) {seq2.pb(tmp);taken2[tmp]=1;} for(int x:adj2[tmp]){ ind2[x]--; if(ind2[x]==0){ //seq2.pb(x); q2.push(x); //taken2[x]=1; } } } vector<vector<int>> dp(n+1, vector<int>(n+1, 0)); for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++){ if(seq[i-1]==seq2[j-1]) dp[i][j]=dp[i-1][j-1]+1; else{ dp[i][j]=max(dp[i-1][j], dp[i][j-1]); } } } cout<<dp[n][n]; }
AC
因為你會發現
兩個拓撲排序順序的結果都會是
一條1~N的排列
這樣可以透過將LCS透過歸約成LIS將複雜度壓到O(N logN)

為什麼呢 大家可以自己回家想想看
絕對不是我懶
# PRESENTING CODE
AC CODE
#include <bits/stdc++.h> using namespace std; #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int n, m;cin>>n>>m; vector<int> ind(n, 0); vector<vector<int>> adj(n); for(int i=0; i<m; i++){ int a, b;cin>>a>>b; adj[a].pb(b); ind[b]++; } priority_queue<int, vector<int>, greater<int>> q; vector<int> seq; for(int i=0;i<n; i++){ if(ind[i]==0) {q.push(i);} } vector<int> taken(n, 0); while(!q.empty()){ int tmp=q.top();q.pop(); if(!taken[tmp]){ seq.pb(tmp);taken[tmp]=1;} for(int x:adj[tmp]){ ind[x]--; if(ind[x]==0){ q.push(x); } } } int n2, m2;cin>>n2>>m2; vector<int> ind2(n2, 0); vector<vector<int>> adj2(n2); for(int i=0; i<m2; i++){ int a, b;cin>>a>>b; adj2[a].pb(b); ind2[b]++; } priority_queue<int, vector<int>, greater<int>> q2; vector<int> seq2; for(int i=0;i<n; i++){ if(ind2[i]==0) {q2.push(i);} }vector<int> taken2(n2, 0); while(!q2.empty()){ int tmp=q2.top();q2.pop(); if(!taken2[tmp]) {seq2.pb(tmp);taken2[tmp]=1;} for(int x:adj2[tmp]){ ind2[x]--; if(ind2[x]==0){ q2.push(x); } } } vector<int> tmp(n); for(int i=0; i<n; i++){ tmp[seq2[i]]=i; } for(int i=0; i<n; i++){ seq[i]=tmp[seq[i]]; } vector<int> LIS; for(int i = 0; i < n; ++i) { int buf=seq[i]; if(LIS.empty() || buf > LIS.back()) { LIS.push_back(buf); } else { auto p = lower_bound(LIS.begin(), LIS.end(), buf); *p = buf; } }cout<<LIS.size(); }
{pD}
我不會DP
題目
分組背包我是出完才知道有分組背包這東西的
如果妳會背包問題你就應該會的東西
多選一或0
subtask 1 1p
暴力計算當前得分
#include<bits/stdc++.h> #define int long long using namespace std; signed main(){ ios_base::sync_with_stdio(false),cout.tie(0),cin.tie(0); int n,T,cnt=0; cin>>n>>T; vector<vector<int>> score(n); vector<vector<bool>> solved(n); for(int i=0,a;i<n;i++){ cin>>a; solved[i].resize(a,false); for(int j=0,v;j<a;j++) cin>>v,score[i].push_back(v); } for(int i=0,c;i<n;i++){ cin>>c; for(int j=0,b;j<c;j++) cin>>b,solved[i][b]=true,cnt+=score[i][b]; } cout<<cnt<<"\n"; }
然後你就會發現你也過了
subtask2和subtask4
subtask 1,2,4 5p
subtask 3
計算完初始得分後,判斷當前時間是否夠在解一次
#include<bits/stdc++.h> #define int long long using namespace std; signed main(){ ios_base::sync_with_stdio(false),cout.tie(0),cin.tie(0); int n,T,cnt=0; cin>>n>>T; vector<vector<int>> score(n); vector<vector<bool>> solved(n); for(int i=0,a;i<n;i++){ cin>>a; solved[i].resize(a,false); for(int j=0,v;j<a;j++) cin>>v,score[i].push_back(v); } for(int i=0,c;i<n;i++){ cin>>c; for(int j=0,b;j<c;j++) cin>>b,solved[i][b]=true,cnt+=score[i][b]; } int k,s,t; cin>>k; cin>>s>>t; if(t<=T){ for(int u;s--;) cin>>u,cnt+=solved[0][u]?0:score[0][u]; } cout<<cnt<<"\n"; }
#include<bits/stdc++.h> #define int long long using namespace std; signed main(){ ios_base::sync_with_stdio(false),cout.tie(0),cin.tie(0); int n,T,cnt=0; cin>>n>>T; vector<vector<int>> score(n); vector<vector<bool>> solved(n); for(int i=0,a;i<n;i++){ cin>>a; solved[i].resize(a,false); for(int j=0,v;j<a;j++) cin>>v,score[i].push_back(v); } for(int i=0,c;i<n;i++){ cin>>c; for(int j=0,b;j<c;j++) cin>>b,solved[i][b]=true,cnt+=score[i][b]; } int k,s,t; cin>>k; cin>>s>>t; if(t<=T){ for(int u;s--;) cin>>u,cnt+=solved[0][u]?0:score[0][u]; } cout<<cnt<<"\n"; }
subtask 5
忘記計算目前得分
subtask 6
沒有subtask
subtask 7
直接做背包
#include<bits/stdc++.h> #define int long long using namespace std; signed main(){ ios_base::sync_with_stdio(false),cout.tie(0),cin.tie(0); int n,T,cnt=0; cin>>n>>T; vector<vector<int>> score(n); vector<vector<bool>> solved(n); for(int i=0,a;i<n;i++){ cin>>a; solved[i].resize(a,false); for(int j=0,v;j<a;j++) cin>>v,score[i].push_back(v); } for(int i=0,c;i<n;i++){ cin>>c; for(int j=0,b;j<c;j++) cin>>b,solved[i][b]=true,cnt+=score[i][b]; } vector<int> dp(T+1,cnt); for(int i=0,k,value,s,t;i<n;i++){ cin>>k>>s>>t; value=0; for(int u;s--;) cin>>u,value+=solved[i][u]?0:score[i][u]; for(int j=T;j>=t;j--) dp[j]=max(dp[j],dp[j-t]+value); } cout<<dp[T]<<"\n"; }
subtask 8
沒有比較好做
AC
- 先預處理好已經得到的分數
- 先預處理好每個解法的得分,記得排掉已經通過的
- 利用dpt儲存花費t的時間的最大得分
- 對於每個題目做:
- 對於特定時間:
- 利用dp計算選擇該解法的最大得分
- dpt=max(dpt,dpt−timecosti+valuei)
- i為所有解法
- 記得排掉超出時間的
- 每個題目相互獨立可以直接做
# PRESENTING CODE
AC CODE
#include<bits/stdc++.h> #define int long long using namespace std; signed main(){ ios_base::sync_with_stdio(false),cout.tie(0),cin.tie(0); int n,T,cnt=0; cin>>n>>T; vector<vector<int>> score(n); vector<vector<bool>> solved(n); for(int i=0,a;i<n;i++){ cin>>a; solved[i].resize(a,false); for(int j=0,v;j<a;j++) cin>>v,score[i].push_back(v); } for(int i=0,c;i<n;i++){ cin>>c; for(int j=0,b;j<c;j++) cin>>b,solved[i][b]=true,cnt+=score[i][b]; } vector<int> dp(T+1,cnt); vector<int> cost, value; for(int i=0,k;i<n;i++){ cin>>k; cost.resize(k),value.resize(k); for(int y=0,t;y<k;y++){ cin>>t>>cost[y]; value[y]=0; for(int z=0,u;z<t;z++){ cin>>u; if(!solved[i][u]) value[y]+=score[i][u]; } } for(int j=T,best;j>0;j--){ best=dp[j]; for(int y=0;y<k;y++){ if(j-cost[y]<0) continue; best=max(best,dp[j-cost[y]]+value[y]); } dp[j]=best; } } cout<<dp[T]<<'\n'; }
{pE}
你是電神🉐
題目
有n個人是你的對手,他們編號大的會贏編號小的
會和這些人對打,打每個人需要ai的電力,你有m的電力,你最高是第幾名
subtask 1 1p
你沒體力,打人又要耗體力,輸光
你是最後一名
輸出n+1
#include<bits/stdc++.h> using namespace std; int main(){ int n; cin>>n; cout<<n+1; }
subtask 2,3
沒有比較好做
AC
對於那n個人當中,想一下他們贏的場次
第i個人贏了i場(0-base)
將ai由小到大排序,從小的開始打
計算你能贏多少場
但還沒結束
你需要考慮其他人會不會多贏
你贏的人有沒有在剛剛打贏的人裡面
# PRESENTING CODE
AC CODE
#include<bits/stdc++.h> using namespace std; int main(){ ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0); int n,m,cnt; cin>>n>>m; vector<pair<int,int>> a(n); cnt=0; for(pair<int,int> &i:a) cin>>i.first; for(int i=0;i<n;i++) a[i].second=i; sort(a.begin(),a.end()); for(int i=0;i<n;i++){ if(m>=a[i].first){ m-=a[i].first; cnt++; } else if(i){ m+=a[i-1].first; for(i=0;i<n&&a[i].first<=m;i++){ if(a[i].second==cnt){ cnt++; break; } } break; } else break; } cout<<n+1-cnt<<'\n'; }
{pF}
你聽說過 費馬小定理 嗎
沒聽過的話請去問學測倒數15天的AaW
因為這題他想的 得
題目
給你一個雞兔同籠的問題
喔不對是佑佑807配對問題
算出答案之後要乘上一個奇怪的東西
大概是 (kn)%m
subtask 1 69p
t=1, n<10000
應該不用我教你怎麼算雞兔同籠ㄅ
反正算完之後佑佑跟807的數量取min之後
慢慢乘就會得到答案了
O(∑n)
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int t;cin>>t; while(t--){ int a, b, n, m, k; cin>>a>>b>>n>>m>>k; int tmp=(b*807-a)/805; int tpp=b-tmp; int ans=min(tmp, tpp); int ti=k; for(int i=1; i<n; i++){ ti=(ti*k)%m; }cout<<ans*ti; } }
subtask 2 18p
n<1015
還記得快速冪ㄅ
O(∑log2(n))
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> #define pb push_back #define all(x) x.begin(),x.end() #define ff first #define ss second int fast(int n,int k, int m){ if(k==0) return 1; if(k==1) return n%m; int dx=fast(n, k/2, m)%m; if(k%2) return (((dx*dx)%m)*n)%m; else return (dx*dx)%m; } signed main(){ ios_base::sync_with_stdio(false);cin.tie(0); int t;cin>>t; while(t--){ int a, b, n, m, k; cin>>a>>b>>n>>m>>k; int tmp=(b*807-a)/805; int tpp=b-tmp; int ans=min(tmp, tpp); int ti=fast(k, n, m); cout<<ans*ti<<'\n'; } }
AC
n<1087
所以甚麼是 費馬小定理 ?
ap≡a (mod p)
若a非p的倍數
ap−1≡1 (mod p)
所以哪裡要用到費馬小定理?
AC
我們來解讀一下
n 除以[m−(1到m之間所有和m的最大公因數大於1的數的數量)]
的商為非負整數且m為質數
[m−(1到m之間所有和m的最大公因數大於1的數的數量)]
(1到m之間所有和m的最大公因數大於1的數的數量)
甚麼意思?
[1, m-1]中和m不互質的數字的個數
[1, m-1]中和m互質的數字的個數
不是阿m就質數當然跟每個人互質 所以是m-1
n是m-1的倍數
AC
n是m-1的倍數
所以呢
kn%m是甚麼?
kd∗(m−1) % m
km−1d % m
1d % m
1
對於每筆詢問
請直接輸出佑佑807配對結果的對數
如果你說
不是阿幹誰知道費馬小定理是甚麼
請認真看題敘
其中一段為
AaW 跑去問佑佑:「教我費馬大定理」
「I consider 小的 to be better than 大的。」佑佑說。
which means, 費馬小定理
我們沒有限制網路搜索喔
下學期可能第一堂課會有你們學長的學長的學長來教你們數學
就是那個每次小社賽都在炸魚的lemonilemon
聽起來好老歐
我本來在想會不會有人無聊亂試直接算完丟上去讓他跑
結果大家都太乖ㄌ
這種沒有penalty的比賽就是要亂丟阿
狂丟
丟到主機炸掉
不對 我要被隔壁的老師罵了
大家有發現我們大小設賽怎麼取題目名字的嗎
Code
By ckefgisc28th
Code
- 139