C
题意: 给定长度为n的01序列,在两个数之间插入一个0或者1,形成一个序列叫做扩展。求f(1,1)+f(1,2)+f(1,3)+f(1,n). f是说有多少个扩展,满足扩展的所有奇数位置都是到那个位置为止的中位数。(也可以理解成出现次数更多)
思路: 反正这个题意有点抽象,但是读读样例能读懂。扩展的奇数位置就是原序列的每个位置,然后出现次数比另一个数多。当时想的是dp,表示每个位置有多少个灵活使用的空位。如果不需要灵活使用的空位,这些位置就是01任选,2的幂次的贡献,如果需要把所有灵活使用的空位都用上,那贡献只能是1. (晚上太困了,忘了由i-1的状态转移到i,不然还能上波分,问题不大,主要是理解的不够深)
PS: 如果第i位为1,第i个位置至少有i个1.因为扩展之后长度是2*i-1,如果要是中位数,至少需要i个1才可以。
题解更简单,如果第i个位置和第i-1个位置是一样的,那么贡献就是前i-1个位置的2倍,否则直接变为1.
其实很有道理,不妨用01来说明,现在两个位置都是1. 因为前i-1个位置是可以内部变换满足中位数那个限制的,也就是说前i-1个位置至少有i-1个1,不然他是满足不了限制的,而第i个位置又是1,前i个位置有i个1,已然满足条件,他前边的空位就01任选了。
而如果两个位置是01,前i-1个位置至少有i-1个0,1至多是i-2个,前i个位置有i-1个1,所以多出来的空位只能填1了。而且此时前i-1个空位也受到限制,只有一种方案了。因为前i-1个位置,恰好0比1多一个是一种方案,如果某个位置再多一个1变成0,最后第i个位置的1和空位的1都不足以让1的数量更多了。(这个我感觉难理解一些,但是当时手摸样例的时候就感觉是这样的,经典瞎猜)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
const int mod = 998244353;
int n,m,k,T;
char s[N];
void solve()
{
scanf("%d",&n);
scanf("%s",s+1);
ll ans = 0;
ll now = 0;
for(int i=1;i<=n;++i)
{
if(s[i]==s[i-1]) now = now * 2 % mod;
else now = 1;
ans = (ans + now) % mod;
}
printf("%lld\n",ans);
}
signed main(void)
{
s[0] = 'a';
scanf("%d",&T);
while(T--)
solve();
return 0;
}
D
题意: 交互题,给定0到n-1的permutation。可以询问2n次,每次问两个不同下标的数的gcd。最后输出x、y,满足ax=0或者ay=0,就是找0在哪个下标。
思路: 基本是两次操作搞定一个数,但是没想明白,看了严格鸽题解才会。
首先n=2,特判,直接输出即可。
令x=1,y=2。始终维护两个有可能为0的下标。
此时比较gcd(x,3),gcd(y,3).
如果二者相等,3的位置不可能是0,不然不会相等,因为x和y不相等,gcd(0,x) = x.
如果二者不相等,假设gcd(x,3) < gcd(y,3)
那么可以排除x的位置是0的可能性。如果x的位置是0,gcd(x,3) = 3,不可能< gcd(y,3)的,gcd(y,3)顶多也就是3。所以令x = i,x的可能性排除但是i还不知道。
反之,可以排除y。
这样依次遍历3-n,即可排除掉n-2个非法下标,最后0一定在里边。太妙了,学不来。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4+10;
int n,m,k,T;
int ask(int i,int j)
{
cout<<"?"<<" "<<i<<" "<<j<<"\n";
int x; cin>>x;
return x;
}
void solve()
{
cin>>n;
int x = 1,y = 2;
for(int i=3;i<=n;++i)
{
int t1 = ask(x,i);
int t2 = ask(y,i);
if(t1==t2) continue;
if(t1<t2) //x的位置一定不是0,如果是0的话gcd更大
{
x = i;
}
else y = i;
}
cout<<"!"<<" "<<x<<" "<<y<<"\n";
cin>>n;
}
signed main(void)
{
srand(time(NULL));
// ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>T;
while(T--)
{
// cout<<"?\n";
solve();
}
return 0;
}