Terraria
2021-05-27 18:58:13
设有
则需要从
首先,可以从
枚举
可以得到
从而
从而
其中
接下来问题就是从
这可以通过高斯消元解决。
询问次数:
当然对于这一部分分可以采取无脑暴力,即每次改一道题目的答案,判断返回的正确题目数量与原有的正确题目数量的大小。这里不过多赘述。
期望得分:
当
1110
1011
1101
即可以用
询问次数:
期望得分:
#include<bits/stdc++.h>
#define check(cnt) if(cnt==n) {print();return 0;}
using namespace std;
char a[10009];
char b[10009];
int cnt1,cnt2;
int n,lim,k,t;
int now=1;
void print(){
for(int i=1;i<=n;i++) cout<<b[i];
cout<<'\n';
cout.flush();
}
void prin(){
for(int i=1;i<=n;i++) cout<<a[i];
cout<<'\n';
cout.flush();
}
int ft(){
int cnt=0;
for(int i=1;i<=now-1;i++){
if(b[i]=='Y') cnt++;
}
return cnt;
}
void doit(){
for(int i=1;i<=n;i++) a[i]='Y';
}
int main(){
cin>>n>>lim;
for(int i=1;i<=n;i++) b[i]=a[i]='Y';
prin();
cin>>t;
//check(t);
while(now<=n){
doit();
a[now]=a[now+1]='N';
prin();
cin>>cnt1;
//check(cnt1);
if(cnt1==t-2||cnt1==t+2){
if(cnt1==t-2) b[now]=b[now+1]='Y';
else b[now]=b[now+1]='N';
now+=2;
if(now==n+1) break;
if(now>n){
now-=2;
break;
}
continue;
}
a[now]='Y',a[now+1]=a[now+2]=a[now+3]='N';
prin();
cin>>cnt1;
//check(cnt1);
a[now]=a[now+2]='N',a[now+1]=a[now+3]='Y';
prin();
cin>>cnt2;
//check(cnt2);
if(cnt1==t-3){
b[now]='N',b[now+1]=b[now+2]=b[now+3]='Y';
}
else if(cnt1==t-1){
if(cnt2==t-2) b[now]=b[now+2]=b[now+3]='Y',b[now+1]='N';
if(cnt2==t) b[now]=b[now+3]='N',b[now+1]=b[now+2]='Y';
if(cnt2==t+2) b[now]=b[now+2]='N',b[now+1]=b[now+3]='Y';
}
else if(cnt1==t+1){
if(cnt2==t-2) b[now]=b[now+2]='Y',b[now+1]=b[now+3]='N';
if(cnt2==t) b[now]=b[now+3]='Y',b[now+1]=b[now+2]='N';
if(cnt2==t+2) b[now]=b[now+2]=b[now+3]='N',b[now+1]='Y';
}
else if(cnt1==t+3){
b[now]='Y',b[now+1]=b[now+2]=b[now+3]='N';
}
now+=4;
if(now==n+1) break;
if(now>n){
now-=4;
break;
}
}
int rest=n-now+1,k=ft();
if(rest==1){
if(k==t) b[n]='N';
else b[n]='Y';
}
else if(rest==2){
if(k==t){
b[n-1]=b[n]='N';
}
else if(k==t-2){
b[n-1]=b[n]='Y';
}
else{
b[n-1]='Y',b[n]='N';
print();
cin>>cnt1;
check(cnt1);
b[n-1]='N',b[n]='Y';
print();
cin>>cnt1;
check(cnt1);
return 0;
}
}
else if(rest==3){
if(k==t){
b[n-2]=b[n-1]=b[n]='N';
}
else if(k==t-3){
b[n-2]=b[n-1]=b[n]='Y';
}
else if(k==t-1){
b[n-2]=b[n-1]=b[n]='N';
b[n-2]='Y',print();
cin>>cnt1;
check(cnt1);
b[n-2]=b[n-1]=b[n]='N';
b[n-1]='Y',print();
cin>>cnt1;
check(cnt1);
b[n-2]=b[n-1]=b[n]='N';
b[n]='Y',print();
cin>>cnt1;
check(cnt1);
}
else if(k==t-2){
b[n-2]=b[n-1]=b[n]='Y';
b[n-2]='N',print();
cin>>cnt1;
check(cnt1);
b[n-2]=b[n-1]=b[n]='Y';
b[n-1]='N',print();
cin>>cnt1;
check(cnt1);
b[n-2]=b[n-1]=b[n]='Y';
b[n]='N',print();
cin>>cnt1;
check(cnt1);
}
}
print();
return 0;
}
【附】这个代码的思路:
记 Y
的个数,即先用一次提交得到
令
把第 N
,如果得到的正确答案数量为
如果返回的是第
把
k,k+1,k+2,k+3 道题依次改为YNNN
,返回m_1 。把
k,k+1,k+2,k+3 道题一次改为NYNY
,返回m_2 。
可以根据
至于如何得到答案,具体可以参见上面代码,这里不过多赘述。
当
1011111100
0010100010
1110000101
1101100011
1100101100
1111100101
0101001101
即可以用
询问次数:
期望得分:
#include <bits/stdc++.h>
using namespace std;
const int magic[7] = {
0b1011111100,
0b0010100010,
0b1110000101,
0b1101100011,
0b1100101100,
0b1111100101,
0b0101001101,
};
map < vector <int>, int > mp;
void init() {
for (int i = 0; i < (1 << 10); i++) {
vector <int> t;
for (int j = 0; j < 7; j++)
t.push_back(__builtin_popcount(i & magic[j]));
mp[t] = i;
}
}
int n;
int query(vector <int> A) {
string S;
for (int i = 0; i < n; i++)
S += 'Y';
for (int i = 0; i < (int)A.size(); i++)
if (A[i] < n) S[A[i]] = 'N';
printf("%s\n", S.c_str());
fflush(stdout);
int res;
scanf("%d", &res);
if (res == n) exit(0);
return res;
}
int K;
vector <int> ans;
int main() {
init();
cin >> n >> K;
int lst = query({});
for (int i = 0; i < n; i += 10) {
vector <int> t;
for (int j = 0; j < 7; j++) {
vector <int> tmp;
for (int k = 0; k < 10; k++)
if (magic[j] >> k & 1)
if (i + k < n)
tmp.push_back(i + k);
t.push_back((query(tmp) - lst + (int)tmp.size()) / 2);
}
int f = mp[t];
for (int k = 0; k < 10; k++)
if (f >> k & 1) ans.push_back(i + k);
}
query(ans);
return 0;
}
题目要求
首先,当
接下来,我们用
时间复杂度:
证明
可以证明这个矩阵满足条件。
设
那么根据奇偶性,
接下来可以解方程组得出
于是得到两个
原问题
因为
期望得分:
但是这样仍然不够优秀,我们可以——
为做出区分,令
现在要求
首先,当
接下来,我们用
其中将
证明
可以证明这个矩阵满足条件。
设
解方程组得
再解方程组得出
时间复杂度:
期望得分:
代码:
#include <bits/stdc++.h>
using namespace std;
#define forn(i, n) for (int i = 0, _n = n; i < _n; i++)
#define pb push_back
typedef vector <int> vi;
typedef vector <vi> vii;
vii A[15];
void gA(int m) {
if (m == 0) {
A[0] = {{1}};
return ;
}
vii &L = A[m - 1], &R = A[m];
forn(i, L.size()) {
vi t;
forn(j, L[i].size()) t.pb(L[i][j]);
forn(j, L[i].size()) t.pb(-L[i][j]);
forn(j, L.size()) t.pb(i == j);
R.pb(t);
}
forn(i, L.size()) {
vi t;
forn(j, L[i].size()) t.pb(L[i][j]);
forn(j, L[i].size()) t.pb(L[i][j]);
forn(j, L.size()) t.pb(0);
R.pb(t);
}
}
vi operator + (vi x, vi y) {
x.insert(x.end(), y.begin(), y.end());
return x;
}
vi dA(int m, vi r) {
if (m == 0) {
return r;
}
int l = A[m - 1].size();
vi x, y, z;
for (int i = 0; i < l; i++) {
z.pb(((r[i] + r[l + i]) % 2 + 2) % 2);
x.pb((r[l + i] + (r[i] - z[i])) / 2);
y.pb((r[l + i] - (r[i] - z[i])) / 2);
}
return dA(m - 1, x) + dA(m - 1, y) + z;
}
vii B[15];
void gB(int m) {
if (m == 1) {
B[1] = {{1}, {0}};
return ;
}
vii &L = B[m - 1], &V = A[m - 1], &R = B[m];
forn(i, L.size()) {
vi t;
forn(j, L[i].size()) t.pb(L[i][j]);
forn(j, V[i].size()) t.pb(V[i][j] == 1);
R.pb(t);
}
forn(i, L.size()) {
vi t;
forn(j, L[i].size()) t.pb(L[i][j]);
forn(j, V[i].size()) t.pb(V[i][j] == -1);
R.pb(t);
}
}
vi dB(int m, vi r) {
if (m == 1) {
return {r[0]};
}
int l = B[m - 1].size();
vi x, y;
for (int i = 0; i < l; i++) {
x.pb(r[i] - r[l + i]);
}
x = dA(m - 1, x);
for (int i = 0; i < l; i++) {
int t = r[i];
for (int j = 0; j < (int)x.size(); j++) {
t -= x[j] * (A[m - 1][i][j] == 1);
}
y.pb(t);
}
y = dB(m - 1, y);
return y + x;
}
int n;
double K;
int query(vi A) {
string S;
for (int i = 0; i < n; i++)
S += "YN"[A[i]];
printf("%s\n", S.c_str());
fflush(stdout);
int res;
scanf("%d", &res);
if (res == n) exit(0);
return res;
}
int popcnt(vi x) {
int c = 0;
for (auto i : x) c += i;
return c;
}
int main() {
cin >> n >> K;
for (int i = 0; i < 11; i++) gA(i);
for (int i = 1; i < 11; i++) gB(i);
int c = 1;
while (B[c][0].size() < n) c++;
vi ret;
ret.clear();
for (int i = 0; i < B[c].size(); i++) {
ret.pb(query(B[c][i]));
}
int lst = ret.back();
for (int i = 0; i < B[c].size(); i++) {
ret[i] = (ret[i] - lst + popcnt(B[c][i])) / 2;
}
vi ans = dB(c, ret);
query(ans);
return 0;
}
特别鸣谢
感谢 曾铭豪 大佬对这道题解法、标程、数据等多方面的建议、启发和指导。