传送门
都高一了才第一次打 好像太菜了点。。。
C
按 排序输出即可
D
枚举中间值,双指针往中间值靠
E
太菜了打的时候只会直接 ,,大概是 表示第 位,匹配了 的方案数
这个瓶颈在于每次状态可能从 变成 ,也就是说之前选的都不算在前缀,现在重新开始匹配
考虑优化这个过程,我们在 后面加上通配符,每次强制匹配,这样每层的状态就是
using namespace std;
typedef long long ll;
cs int N = 3e3 + 50;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
char S[N], T[N]; int n, m;
int dp[N][N];
int main(){
freopen("1.in","r",stdin);
scanf("%s%s",S+1,T+1); n=strlen(S+1); m=strlen(T+1);
for(int i=1; i<=m; i++) if(S[1]==T[i]) dp[i][i]=2;
for(int i=m+1; i<=n; i++) dp[i][i]=2;
for(int i=2; i<=n; i++)
for(int l=1; l<=n; l++){
int r=l+i-1; if(r>n) break;
if(r>m||S[i]==T[r]) Add(dp[l][r],dp[l][r-1]);
if(l>m||S[i]==T[l]) Add(dp[l][r],dp[l+1][r]);
} int as = 0;
for(int i=m; i<=n; i++) Add(as,dp[1][i]);
cout << as;
return 0;
}
F
交互题:初始集合是值域 ,每个数出现次数 的集合,你可以知道当前集合中形如 的子集个数,每次可以插入一个数,要猜出初始集合,插入次数
有插 次直接得到答案的,每 3 个分组可以插 次得到答案
每个插一次可以 得到答案,那么我们将上述方法结合一下,就有如下巧妙的构造
考虑插 2 次可以确定 ,那么我们先插 ,知道 ,然后插 ,再插 得到 ,这样就可以得到 ,进一步得到
那么最终的策略可以为:从 插到 ,插 ,插 ,插 ,然后顺推到
最巧妙的地方就是将 分到两次加,可以多获得一个信息
using namespace std;
cs int N = 105;
typedef long long ll;
ll A, B, dA, dB;
int n; ll a[N], b[N];
void work(int u){
cout<<"+ "<<u<<endl<<endl;
dA=A; dB=B;
scanf("%lld%lld",&A,&B); dA=A-dA; dB=B-dB;
}
int get(ll x){
if(x==0) return 1;
for(int i=2; i<=n+2; i++) if((i*(i-1)>>1)==x) return i;
}
int main(){
freopen("1.in","r",stdin);
scanf("%d",&n);
scanf("%lld%lld",&A,&B);
memset(a,-1,sizeof(a));
for(int i=2; i<=n-2; i++){
work(i); b[i]=dB;
} work(n); ll dt=dB;
work(n-1); b[n-1]=dB;
work(n); a[n]=get(dA)-1;
a[n-2]=dB-dt-1;
a[n-1]=dt/(a[n-2]+1);
b[n-1]-=(a[n-2]+1)*(a[n]+1);
for(int i=n-3; i>=1; i--){
a[i]=b[i+2]/(a[i+1]+1)-(i>1);
b[i+1]-=a[i+2]*a[i+3];
b[i+1]-=a[i+2]*(a[i]+1);
}
cout<<"! ";
for(int i=1; i<=n; i++) cout<<a[i]<<" ";
cout<<endl<<endl;
}