{小社題解}
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
\(a_i=0\) 所有人都連上了代表交換器的0
算 \(n+\sum b_i\)
\(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
\(b_i=N\) 所有人都可以被 \(N\) 個人連上
不用擔心會有人連到不該連的 一定夠
對於每次連接 若接上交換器則答案加\(b_i+1\) 否則加\(b_i\)
\(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(N^2)\) 的解法就可喇(?
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 \le 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 \le 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(N^2)\)
你會發現會炸 壓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";
}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
- 先預處理好已經得到的分數
- 先預處理好每個解法的得分,記得排掉已經通過的
- 利用\(dp_t\)儲存花費\(t\)的時間的最大得分
- 對於每個題目做:
- 對於特定時間:
- 利用dp計算選擇該解法的最大得分
- \(dp_t=max(dp_t,dp_{t-timecost_i}+value_i)\)
- \(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\)個人是你的對手,他們編號大的會贏編號小的
會和這些人對打,打每個人需要\(a_i\)的電力,你有\(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)
將\(a_i\)由小到大排序,從小的開始打
計算你能贏多少場
但還沒結束
你需要考慮其他人會不會多贏
你贏的人有沒有在剛剛打贏的人裡面
# 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配對問題
算出答案之後要乘上一個奇怪的東西
大概是 \((k^n)\%m\)
subtask 1 69p
$$ t=1, n < 10000 $$
應該不用我教你怎麼算雞兔同籠ㄅ
反正算完之後佑佑跟807的數量取min之後
慢慢乘就會得到答案了
\(O(\sum 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 < 10^{15} $$
還記得快速冪ㄅ
\(O(\sum log_2(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 < 10^{87} $$
所以甚麼是 費馬小定理 ?
\(a^p \equiv a \ (mod \ p)\)
若a非p的倍數
\(a^{p-1} \equiv 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的倍數
所以呢
\(k^n\%m\)是甚麼?
\(k^{d*(m-1)} \ \%\ m\)
\( {k^{m-1}}^d \ \%\ m\)
\(1^d \ \% \ m\)
1
對於每筆詢問
請直接輸出佑佑807配對結果的對數
如果你說
不是阿幹誰知道費馬小定理是甚麼
請認真看題敘
其中一段為
AaW 跑去問佑佑:「教我費馬大定理」
「I consider 小的 to be better than 大的。」佑佑說。
which means, 費馬小定理
我們沒有限制網路搜索喔
下學期可能第一堂課會有你們學長的學長的學長來教你們數學
就是那個每次小社賽都在炸魚的lemonilemon
聽起來好老歐
我本來在想會不會有人無聊亂試直接算完丟上去讓他跑
結果大家都太乖ㄌ
這種沒有penalty的比賽就是要亂丟阿
狂丟
丟到主機炸掉
不對 我要被隔壁的老師罵了
大家有發現我們大小設賽怎麼取題目名字的嗎
Code
By ckefgisc28th
Code
- 176