2021-2022 ACM-ICPC Brazil Subregional Programming Contest
C. Creating Multiples
-
題意:有一個長度為\(n\)的\(B\)進制數,問你能否減小某一位上的數,使得其可以整除\(B+1\),輸出修改的位置和修改后的數,如果不能滿足條件輸出\(-1,-1\),不用修改則輸出\(0,0\).
-
題解:假設原數在十進制下的數為\(N\),那么有\(N\equiv r\mod (B+1)\),修改后的新數為\(N'\equiv= 0 \mod (B+1)\),所以要滿足\(N-r\equiv 0\mod (B+1)\),假設我們修改第\(i\)個位置上的數\(a_i\),得到新位置上的數為\(c_i\),那么有\((a_i-c_i)*b^i\equiv r\mod (B+1)\),\(a_i-c_i\equiv r*b^{-i}\mod (B+1)\),而\(a_i-c_i\)表示修改后的差值,顯然差值的范圍是\([1,a_i]\),那么只要\(r*b^{-i} \le a_i\)就滿足條件,直接輸出即可,記得特判不需要修改的情況。這里采取的是擴歐法求逆元。
-
代碼:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} ll b,l; ll d[N]; ll x,y; ll sum[N],inv[N]; ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1,y=0; return a; } ll x_,y_; ll d=exgcd(b,a%b,x_,y_); x=y_,y=x_-a/b*y_; return d; } ll cal(ll x){ ll _x,_y; ll d=exgcd(x,b+1,_x,_y); return (_x%(b+1)+b+1)%(b+1); } int main() { scanf("%lld %lld",&b,&l); for(int i=1;i<=l;++i){ scanf("%lld",&d[i]); } reverse(d+1,d+1+l); ll base=1; for(int i=1;i<=l;++i){ sum[i]=(sum[i-1]+d[i]*base%(b+1))%(b+1); inv[i]=cal(base); base=base*b%(b+1); } if(sum[l]==0){ puts("0 0"); return 0; } ll m=sum[l]; reverse(d+1,d+1+l); for(int i=1;i<=l;++i){ ll now=m*inv[l-i+1]%(b+1); if(now<=d[i]){ printf("%d %lld\n",i,d[i]-now); return 0; } } puts("-1 -1"); return 0; }
E. Escalator
-
題意:有一個雙向的電動扶梯,一個乘客從起點到終點需要10s的時間,當沒有乘客時,電梯會自動停止,下次開始時可以朝任意方向運行,當電梯朝着某一方向運行時,必須將這個方向的乘客送完才會停止,現在有\(n\)個乘客,每個乘客都有各自的乘坐起點時間和方向,問你最早什么時候所有乘客都能到達目的地。
-
題解:一個策略是電梯朝某一方向一直運行直到某一時刻沒有乘客乘坐停止,方向相同且起點時刻在這段時間內的乘客都坐上去,停止后,判斷哪個方向的乘客起始時刻更近,就朝哪個方向運行,一直這樣運行下去,同時注意更新時間即可。
-
代碼:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n; PII pt[N]; vector<ll> l,r; int main() { scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d %d",&pt[i].fi,&pt[i].se); if(pt[i].se==0) l.pb(pt[i].fi); else r.pb(pt[i].fi); } int i=0,j=0; int dir=pt[1].se; ll now=0; bool flag=false; while(i<(int)l.size() && j<(int)r.size()){ if(dir==0){ if(!flag) now=max(now,l[i]+10); else{ now=max(now,l[i])+10; flag=false; } i++; if(i>=(int)l.size()){ dir=1; flag=true; continue; } if(now<l[i] && r[j]<l[i]){ // change the direction dir=1; flag=true; } } else{ if(!flag) now=max(now,r[j]+10); else{ now=max(now,r[j])+10; flag=false; } j++; if(j>=(int)r.size()){ dir=0; flag=true; continue; } if(now<r[j] && l[i]<r[j]) dir=0,flag=true; } } while(i<(int)l.size()){ if(!flag) now=max(now,l[i]+10); else{ now=max(now,l[i])+10; flag=false; } i++; } while(j<(int)r.size()){ if(!flag) now=max(now,r[j]+10); else{ now=max(now,r[j])+10; flag=false; } j++; } printf("%lld\n",now); return 0; }
G. Getting in Shape
-
題意:有兩種練習\(A\)和\(B\),B表示做完后繼續做一下個,\(A\)表示做完后可以選擇繼續做下一個或者跳過下一個直接做下下個,現在讓你構造一個練習的序列,序列的最后以\(B\)結尾,使得做練習的所有情況剛好為\(n\)。
-
題解:因為\(B\)不會產生任何多余的貢獻,貢獻只和\(A\)有關,我們看\(AB,AAB,AAAB\)不難發現這些情況數一個斐波那契數列,那么將他們拼接在一起,貢獻是相乘的關系,所以問題也就轉化成了用這些斐波那契數相乘能否得到\(n\),直接dfs找即可。
-
代碼:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} ll n; ll f[N]; int cnt; vector<int> v,ans; bool flag; void dfs(int u,ll now){ if(flag) return; if(now==1){ ans=v; flag=true; return; } for(int i=u;i>=1;--i){ if(f[i]>now || now%f[i]) continue; v.pb(i); dfs(i,now/f[i]); v.pop_back(); } } int main() { f[1]=2,f[2]=3; for(int i=3;i<=80;++i){ if(f[i-2]+f[i-1]>1000000000000000) break; cnt=i; f[i]=f[i-2]+f[i-1]; } scanf("%lld",&n); dfs(cnt,n); if(flag){ for(auto w:ans){ for(int i=1;i<=w;++i){ printf("A"); } printf("B"); } } else puts("IMPOSSIBLE"); return 0; }
H. Handling the Blocks
對每個顏色的數排序,然后判斷即可
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int n,k;
PII pt[N];
int pos[N];
vector<int> col[N];
queue<int> q[N];
int a[N];
int main() {
scanf("%d %d",&n,&k);
for(int i=1;i<=n;++i){
scanf("%d %d",&pt[i].fi,&pt[i].se);
pos[i]=pt[i].se;
col[pt[i].se].pb(pt[i].fi);
}
for(int i=1;i<=k;++i){
sort(col[i].begin(),col[i].end());
for(auto w:col[i]) q[i].push(w);
}
bool flag=true;
for(int i=1;i<=n;++i){
int now=pos[i];
a[i]=q[now].front();
q[now].pop();
if(a[i]<a[i-1]){
flag=false;
break;
}
}
if(flag) puts("Y");
else puts("N");
return 0;
}
K. Kathmandu
枚舉判斷一下區間是否合法即可
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int t,d,m;
int a[N];
int main() {
scanf("%d %d %d",&t,&d,&m);
a[1]=0;
for(int i=2;i<=m+1;++i) scanf("%d",&a[i]);
a[m+2]=d;
bool flag=false;
for(int i=1;i<=m+2;++i){
if(a[i]-a[i-1]>=t){
flag=true;
break;
}
}
if(flag) puts("Y");
else puts("N");
return 0;
}
M. Monarchy in Vertigo
-
題意:剛開始只有一個編號為\(1\)的人,他是國王,操作1表示編號為\(x\)的生了一個孩子,每個人的編號都是唯一的,操作2表示編號為\(x\)的人g了,假如是國王g了,就要選擇新的國王,選舉策略是,優先選孩子(一直向下選孩子父親->兒子->孫子->曾孫子),如果沒孩子,就選最近的兄弟,然后再看兄弟的兒子。。。。,問你每次有人死去的時候,當前的國王是誰
-
題解:很明顯,生一個孩子相當於父節點加了一個兒子結點,選舉國王就是一個dfs序,我們先離線將樹建好,然后跑一遍dfs,把序列求出,之后再用鏈表進行操作,每次輸出頭結點對應的值即可。
-
代碼:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n; int idx; PII pt[N]; vector<int> edge[N]; vector<int> v; int head,e[N],ne[N],pre[N]; int pos[N]; void dfs(int u,int fa){ v.pb(u); for(auto to:edge[u]){ if(to==fa) continue; dfs(to,u); } return; } int main() { scanf("%d",&n); idx=1; for(int i=1;i<=n;++i){ scanf("%d %d",&pt[i].fi,&pt[i].se); if(pt[i].fi==1) edge[pt[i].se].pb(++idx); } dfs(1,-1); head=0; ne[head]=1; for(int i=1;i<=(int)v.size();++i){ e[i]=v[i-1]; ne[i]=i+1; pre[i]=i-1; pos[v[i-1]]=i; } for(int i=1;i<=n;++i){ if(pt[i].fi==2){ int now=pos[pt[i].se]; pre[ne[now]]=pre[now]; ne[pre[now]]=ne[now]; printf("%d\n",e[ne[head]]); } } return 0; }
N. No Luck
主席樹求區間中不小於\(k\)的數出現次數的裸題。。。。
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int y,n;
int x[N];
int a[N],p[N],f[N];
int root[N],idx;
struct Node{
int l,r;
int cnt;
}tr[N<<4];
int build(int l,int r){
int p=++idx;
if(l==r) return p;
int mid=(l+r)>>1;
build(l,mid),build(mid+1,r);
return p;
}
int update(int p,int l,int r,int x){
int q=++idx;
tr[q]=tr[p];
tr[q].cnt++;
if(l==r) return q;
int mid=(l+r)>>1;
if(x<=mid) tr[q].l=update(tr[p].l,l,mid,x);
else tr[q].r=update(tr[p].r,mid+1,r,x);
return q;
}
int query(int L,int R,int l,int r,int k){
if(l>=k) return tr[R].cnt-tr[L].cnt;
if(l==r) return tr[R].cnt-tr[L].cnt;
int mid=(l+r)>>1;
int res=0;
if(k<=mid) res=query(tr[L].l,tr[R].l,l,mid,k)+query(tr[L].r,tr[R].r,mid+1,r,k);
else res=query(tr[L].r,tr[R].r,mid+1,r,k);
return res;
}
int main() {
scanf("%d %d",&y,&n);
root[0]=build(1,100010);
for(int i=1;i<=y;++i){
scanf("%d",&x[i]);
root[i]=update(root[i-1],1,100010,x[i]);
}
for(int i=1;i<=n;++i){
scanf("%d %d %d",&a[i],&p[i],&f[i]);
if(x[a[i]]>=p[i]) puts("0");
else printf("%d\n",query(root[a[i]-1],root[a[i]+f[i]],1,100010,p[i]));
}
return 0;
}