XIX Open Cup, Grand Prix of SPb【雜題】
啊哈,好像學會開火車了 。
感覺單人 vp ACM 有點自閉,但是沒人陪我訓練所以沒辦法了 。
G Least Number
給定正整數 \(n\) 和數字 \(d\),求最小的數字和為 \(n\) 且不含數字 \(d\) 的正整數。
\(2\le n\le 10^6\)。
垃圾分類討論題,隨便測一測就寫完了(
#include<bits/stdc++.h> using namespace std; int n, d; int main(){ ios::sync_with_stdio(false); cin >> n >> d; if(d == 9){ if(n & 7) putchar((n & 7) | '0'); for(int i = n>>3;i;-- i) putchar('8'); } else if(!d || n % 9 != d){ if(n % 9) putchar(n % 9 + '0'); for(int i = n/9;i;-- i) putchar('9'); } else if(d == 8){ putchar('1'); putchar('7'); for(int i = n/9;i;-- i) putchar('9'); } else if(n > 9){ putchar(d + '1'); putchar('8'); for(int i = n/9;i > 1;-- i) putchar('9'); } else printf("1%d\n", n-1); }
F Dominating Subarray
對於兩個長為 \(k\) 的正整數列 \(b,c\),稱 \(b\) 偏序 \(c\) 當且僅當 \(b_i\ge c_i\)。
給定長為 \(n\) 的正整數列 \(a\) 和正整數 \(k\),求一個偏序所有長為 \(k\) 的子段的長為 \(k\) 的子段。
\(k\le n\le 10^5\),\(a_i\le 10^6\)。
\(k=n\) 時顯然有解,否則還是分類討論:
- 若是字首,則 \(a_i\le a_{\min(k,i-1)}\pod{i\ge 2}\);
- 若是字尾,則 \(a_i\le a_{\max(n-k,i)+1}\pod{i<n}\)
- 否則,必須是連續 \(k\) 個最大值。
直接判即可,時間複雜度 \(O(n)\)。
#include<bits/stdc++.h> using namespace std; const int N = 100003; template<typename T> bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;} int n, k, a[N], mx; int main(){ ios::sync_with_stdio(false); cin >> n >> k; if(k == n){putchar('1'); return 0;} for(int i = 1;i <= n;++ i){cin >> a[i]; chmax(mx, a[i]);} bool flg = true; for(int i = 2;i <= n && flg;++ i) flg &= a[i] <= a[min(k,i-1)]; if(flg){putchar('1'); return 0;} flg = true; for(int i = n-1;i && flg;-- i) flg &= a[i] <= a[max(n-k,i)+1]; if(flg){printf("%d", n-k+1); return 0;} for(int i = 2, j = 0;i < n;++ i) if(a[i] == mx){ if(++j == k){printf("%d", i-k+1); return 0;} } else j = 0; puts("-1"); }
D Distance in Crosses
【題目描述略】
顯然十字也構成四連通網格,所以也是算曼哈頓距離。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL xa, ya, xb, yb;
LL div5(LL x){return x >= 0 ? (x+2) / 5 : (x-2) / 5;}
int main(){
ios::sync_with_stdio(false);
cin >> xa >> ya >> xb >> yb;
LL x1 = div5(2*xa+ya), y1 = div5(xa-2*ya), x2 = div5(2*xb+yb), y2 = div5(xb-2*yb);
printf("%lld\n", llabs(x1-x2) + llabs(y1-y2));
}
I Multiplication
這是一道互動題
互動庫有一個奇數 \(x\in[1,2^{31}-1]\),給定正偶數 \(n\),你需要給出 \(n\) 個 \(<2^{31}\) 的不同自然數 \(a_i\),互動庫會隨機抽取其中的 \(n/2\) 個 \(a_i\),將 \(b_i=a_ix\bmod 2^{31}\) 打亂之後告訴你,求 \(x\)。
\(4\le n\le 10^5\)。
你給出的 \(a_i\) 直接取隨機奇數即可。
首先看 \(b_1\),有 \(x^{-1}=a_{?}\cdot b_1^{-1}\),將可能的 \(n\) 個 \(x^{-1}\) 算出來,然後用 \(\forall i,b_i\cdot x^{-1}=a_{?}\) 大力判斷。期望複雜度 \(O(n)\)。
不要貪圖僥倖直接隨機,必須用個 set 去重。
而且這個模 \(2^{31}\) 好陰間啊,能不能直接模 \(2^{32}\) 爽快點(
#include<bits/stdc++.h>
#define PB emplace_back
using namespace std;
const int N = 100003;
const unsigned ALL = -1u>>1;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int n, m, pos[N];
unsigned b[N], ans;
set<unsigned> S;
unsigned Inv(unsigned x){
unsigned res = 1;
for(int i = 1;i < 31;++ i)
if(res*x>>i&1) res |= 1u<<i;
return res;
}
vector<unsigned> res;
int main(){
ios::sync_with_stdio(false);
cin >> n; m = n>>1;
while(S.size() < n) S.insert((rng()&ALL)|1);
for(unsigned u : S) cout << u << ' ';
cout << endl;
for(int i = 0;i < m;++ i)
cin >> b[i];
unsigned tmp = Inv(b[0]);
for(unsigned u : S) res.PB(u*tmp&ALL);
for(int i = 1;i < m && res.size() > 1;++ i){
vector<unsigned> nxt;
for(unsigned x : res){
unsigned tmp = b[i]*x&ALL;
if(S.count(tmp)) nxt.PB(x);
} res.swap(nxt);
}
cout << Inv(res[0]) << endl;
}
A Create the Best Pet
【題目描述略】
也就只能大力列舉判斷了,因為用 Gene 判比較快所以先用 Gene 判再用 Power 判,跑個幾秒就跑出來了。
#include<bits/stdc++.h>
using namespace std;
const unsigned ALL = -1u>>1;
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
struct u31 {
unsigned x;
u31(unsigned a = 0): x(a&ALL){}
u31 operator + (const u31 &o) const {return x + o.x & ALL;}
u31 operator * (const u31 &o) const {return x * o.x & ALL;}
u31 Inv() const {
unsigned res = 1;
for(int i = 1;i < 31;++ i)
if(res*x>>i&1) res ^= 1u<<i;
return res;
}
};
u31 calc(const string &s){
int len = s.size(); u31 res;
for(int i = 0;i < len;++ i)
res = res * 31 + s[i];
return res;
}
int mx, ans[8], info[8];
unsigned pos;
int main(){
unsigned L, R; string str;
ios::sync_with_stdio(false);
cin >> L >> R >> str; R += L;
unsigned _ = /*Magic Number*/^calc(str).x;
for(unsigned i = L;i <= R;++ i){
u31 sd(_ ^ i);
int scr = 0, tmp[8];
for(int i = 0;i < 8;++ i){
tmp[i] = 0;
for(int j = 0;j < 10000;++ j){
sd = sd * 1234567893 + 151515151;
tmp[i] += sd.x % 3 - 1;
}
scr += abs(tmp[i]);
}
if(chmax(mx, scr)){
pos = i;
for(int i = 0;i < 8;++ i) ans[i] = tmp[i] + 500;
for(int i = 0;i < 8;++ i){
sd = sd * 1234567893 + 151515151;
info[i] = sd.x % 5;
}
}
}
printf("%u %.3f\n", pos, mx / 8.);
for(int i = 0;i < 8;++ i) printf("%d ", ans[i]);
putchar('\n');
for(int i = 0;i < 8;++ i) printf("%d ", info[i]);
}
J Guess Two Strings
這是個 jb 的互動題
出題人有兩個長為 \(n\) 的 \(\texttt{01}\) 字串 \(S,T\),他按如下方式生成 \(q\) 個 \(\texttt{01}\) 字串並告訴你,求 \(S,T\):
- 隨機選 \(S\) 或 \(T\) 之一,翻轉隨機的 \(k\) 個 bit。
\(n=q=100\),\(k=15\),\(S\le T\)。
這種東西顯然直接瞎搞搞就行了。
輸入的 \(q\) 個串形成兩個團。隨機列舉其中兩個串,假裝它們屬於不同的團,按其他串到它們的編輯距離劃分成兩個團。求 \(S,T\) 的時候直接對每一位取眾數即可。期望複雜度 \(O(nq)\)。
#include<bits/stdc++.h>
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int n, k, q;
string S[100], ans[2];
bool a[100];
int dis(const string &a, const string &b){
int res = 0;
for(int i = 0;i < n;++ i) res += a[i] != b[i];
return res;
}
bool work(){
int p1 = rng() % q, p2 = rng() % q;
if(p1 == p2) return true;
for(int i = 0;i < q;++ i)
a[i] = dis(S[i], S[p1]) > dis(S[i], S[p2]);
for(int _ = 0;_ < 2;++ _)
for(int i = 0;i < n;++ i){
int cnt[2] = {};
for(int j = 0;j < q;++ j)
if(a[j] == _) ++ cnt[S[j][i] ^ '0'];
ans[_][i] = (cnt[0] < cnt[1]) | '0';
}
for(int i = 0;i < q;++ i)
if(dis(S[i], ans[0]) > k && dis(S[i], ans[1]) > k)
return true;
if(ans[0] > ans[1]) swap(ans[0], ans[1]);
return false;
}
int main(){
ios::sync_with_stdio(false);
cin >> n >> k >> q;
for(int i = 0;i < q;++ i){
cout << '?' << endl;
cin >> S[i];
}
ans[0].resize(n);
ans[1].resize(n);
while(work());
cout << "! " << ans[0] << ' ' << ans[1] << endl;
}
K Beautiful Tables
【題目描述略】
顯然題目條件是每行每列形成等差數列,隨便手玩一下就知道等價於存在四個數 \(a,b,c,d\),使得 \(a_{i,j}=a+bi+cj+dij\),直接解線性方程組即可。
最後蜜汁 WA 沒調出來,賽後仔細看看才發現是分母算出負數了
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, m, cnt;
char str[10];
LL gcd(LL a, LL b){return b ? gcd(b, a % b) : a;}
struct Frac {
LL a, b;
Frac(LL x = 0, LL y = 1){LL g = gcd(x, y); a = x / g; b = y / g; if(b < 0){a = -a; b = -b;}}
Frac operator + (const Frac &o) const {
LL g = gcd(b, o.b);
return Frac(o.b / g * a + b / g * o.a, b / g * o.b);
}
Frac operator - (const Frac &o) const {
LL g = gcd(b, o.b);
return Frac(o.b / g * a - b / g * o.a, b / g * o.b);
}
Frac operator * (const Frac &o) const {
LL g1 = gcd(b, o.a), g2 = gcd(a, o.b);
return Frac(a / g2 * (o.a / g1), b / g1 * (o.b / g2));
}
Frac Inv() const {return Frac(b, a);}
Frac operator / (const Frac &o) const {return this->operator*(o.Inv());}
operator bool() const {return a;}
friend ostream& operator << (ostream& out, const Frac &o){
out << o.a << '/' << o.b; return out;
}
} mat[4][5], tmp[5];
void Ins(Frac *a){
for(int i = 0;i < 4;++ i) if(a[i]){
if(!mat[i][i]){
for(int j = i+1;j < 5;++ j) mat[i][j] = a[j] / a[i];
mat[i][i] = 1; ++cnt; return;
}
for(int j = i+1;j < 5;++ j) a[j] = a[j] - a[i] * mat[i][j];
a[i] = 0;
}
if(a[4]){cout << "None" << endl; exit(0);}
}
int main(){
ios::sync_with_stdio(false);
cin >> n >> m;
if(n == 1){tmp[1] = 1; tmp[0] = tmp[2] = tmp[3] = tmp[4] = 0; Ins(tmp);}
if(m == 1){tmp[2] = 1; tmp[0] = tmp[1] = tmp[3] = tmp[4] = 0; Ins(tmp);}
if(n == 1 || m == 1){tmp[3] = 1; tmp[0] = tmp[1] = tmp[2] = tmp[4] = 0; Ins(tmp);}
for(int i = 0;i < n;++ i)
for(int j = 0;j < m;++ j){
cin >> str;
if(str[0] != '?'){
tmp[0] = 1; tmp[1] = i;
tmp[2] = j; tmp[3] = i*j;
tmp[4] = atoi(str); Ins(tmp);
}
}
if(cnt == 4){
for(int i = 3;~i;-- i){
tmp[i] = mat[i][4];
for(int j = i+1;j < 4;++ j)
tmp[i] = tmp[i] - mat[i][j] * tmp[j];
}
cout << "Unique" << endl;
for(int i = 0;i < n;++ i){
for(int j = 0;j < m;++ j)
cout << tmp[0]+tmp[1]*Frac(i)+tmp[2]*Frac(j)+tmp[3]*Frac(i*j) << ' ';
cout << endl;
}
return 0;
}
for(int i = 3;~i;-- i){
tmp[i] = mat[i][4];
for(int j = i+1;j < 4;++ j)
tmp[i] = tmp[i] - mat[i][j] * tmp[j];
}
cout << "Multiple" << endl;
for(int i = 0;i < n;++ i){
for(int j = 0;j < m;++ j)
cout << tmp[0]+tmp[1]*Frac(i)+tmp[2]*Frac(j)+tmp[3]*Frac(i*j) << ' ';
cout << endl;
}
cout << "and" << endl;
for(int i = 3;~i;-- i){
tmp[i] = mat[i][i] ? mat[i][4] : Frac(1);
for(int j = i+1;j < 4;++ j)
tmp[i] = tmp[i] - mat[i][j] * tmp[j];
}
for(int i = 0;i < n;++ i){
for(int j = 0;j < m;++ j)
cout << tmp[0]+tmp[1]*Frac(i)+tmp[2]*Frac(j)+tmp[3]*Frac(i*j) << ' ';
cout << endl;
}
}
【未完待續】