傳送門
題目大意:給定n個d維向量,輸出任意一對向量,滿足他倆的內積爲k的倍數。
我想了一個裸的隨機算法:隨機選兩個向量求內積,然後。。。後10個點只過了兩個。。。看到標準解法也是用的隨機,一開始感覺非常不服他的隨機到底比我的強在哪。。。(後來發現是我太弱)
值得一提的是,此題必須使用隨機算法來確定答案。只取全1向量的做法是錯誤的。
一組很簡單的數據就能卡掉(不信?試一試)
meow.in
4 6 2
1 1 0 0 0 0
1 1 1 1 0 0
1 1 1 0 0 1
1 0 0 1 1 1
meow.out(樣例)
1 2
題解吧……先放在後面
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
#define rep(I, S, T) for (int I = S; I <= T; I ++)
#define rst(ARR) memset(ARR, 0, sizeof(ARR))
int read(){
int ret = 0; char ch;
do ch = getchar(); while (ch<'0' || ch>'9');
do ret = ret*10+ch-'0', ch = getchar(); while (ch>='0' && ch<='9');
return ret;
}
const int MAXN = 100005;
const int MAXK = 105;
int n, d, k;
int seq[MAXN][MAXK], diag[MAXN], X[MAXN], res[MAXN], Y[MAXN];
void check(int i, int j) {
int sum = 0;
rep(p, 1, d) sum += seq[i][p]*seq[j][p];
sum %=k;
if (sum==0 ) {
if (i>j) swap(i, j);
printf("%d %d\n", i, j);
exit(0);
}
}
void solve2() {
rep(T, 1, 10) {
int s = 0;
rst(res);rst(Y);
rep(i, 1, n) X[i] = rand()%k, s+=X[i];
s%=k;
rep(i, 1, n) rep(j, 1, d) res[j] += seq[i][j]*X[i];
rep(i, 1, d) res[i]%=k;
rep(i, 1, n) {
rep(j, 1, d) Y[i] += res[j]*seq[i][j];
Y[i] += k-diag[i]*X[i];
Y[i]%=k;
}
rep(i, 1, n) if ((Y[i] + X[i])%k!=s)
rep(j, 1, n) if (j!=i)check(i, j);
}
}
void solve3() {
rep(i, 1, n) diag[i]=(bool)diag[i];
rep(T, 1, 7) {
int s = 0;
rep(i, 1, d*d) res[i] = 0;
rep(i, 1, n) X[i] = rand()%k, s+=X[i];
s%=k;
rep(i, 1, n) {
int *s = seq[i], pt = 0;
rep(j, 1, d) rep(p, 1, d) res[++pt] += s[j]*s[p]*X[i];
}
rep(i, 1, d*d) res[i]%=k;
rep(i, 1, n) {
int *sq = seq[i], pt = 0;
Y[i] = 0;
rep(j, 1, d) rep(p, 1, d) Y[i] += res[++pt]*sq[j]*sq[p];
Y[i] += k-diag[i]*X[i]; Y[i]%=k;
if ((Y[i] + X[i])%k!=s)
rep(j, 1, n) if (j!=i) check(i, j);
}
}
}
int main()
{
srand(223333333);
scanf("%d%d%d", &n, &d, &k);
rep(i, 1, n) rep(j, 1, d) seq[i][j] = read()%k;
rep(i, 1, n) {
rep(j, 1, d) diag[i] += seq[i][j]*seq[i][j];
diag[i]%=k;
}
if (k==2) solve2(); else solve3();
puts("-1 -1");
return 0;
}
首先!模型轉換:
好啊!非常優美,但是直接計算複雜度仍然是
暫時只考慮
我們更關心是否存在0元素對吧
可以拿
爲了降低複雜度,我們不能對
根據結合律,計算
(似乎這是判斷矩陣是否相等的經典辦法?)
只要有一個元素不同=>對應列上存在一個0向量,只需要暴力枚舉尋找位置
沒有元素不同=>X選得不好或者本來就沒有
根據定理**,正確概率至少有
(2014年胡澤聰的集訓隊論文可以參考一下)
然後問題來了:
Q1.
A1:這個比較重要,要將干擾排除。幸運的是,只有n個內積需要計算,這樣計算
Q2.爲什麼要隨機。。直接取全一向量不行麼?
A2:設
把
看起來取全一向量非常靠譜,可是不要忘記——我們是在
理想的情況當然應該是先把
網上有一部分沒有使用隨機化的做法,隨便找出一個,就能用開頭的辦法卡掉。
所以靠譜的做法是:在
Q3.同樣是隨機,爲什麼裸隨機不如套用矩陣進行隨機?
A3:別忘了,在標準做法中,每次可以對一整列進行判定,只要有一個出錯,整個就會出錯,而n列的判定問題又可以在
Q4.光顧着說
A4:這一次,矩陣B中不全是1了(有可能是2),不能把它和全一矩陣比較了。
怎麼辦呢?把每一個內積的值平方!因爲
把內積平方拆開:
可以看成一個d^2維向量
這樣就完成了問題轉化,只是需要用
當初上uoj想找一份標程扒一下(因爲太弱了,並不會),發現好多人用了一樣的代碼汗,而且真正用隨機向量的人不多啊。
構造了反例,想Hack一下,可惜那道題是一道spj,沒法Hack
於是出於業(xian)界(zhe)良(mei)心(shi),我想vfk大大發了郵件,希望加強一下數據
結果第二天發現vfk凌晨回覆了郵件!並且添加了Extra Test!這種敬業精神必須要贊!!
我還想加強一下BZOJ數據。。不過TA1111爺似乎也注意到了。。比我早幾天。。那麼我就不把事情做絕了