Problem - D - Codeforces
思路:
- 首先,一个位置至多贡献1,不然就是0.如[l1,r]与[l2,r]都是回文串(l1<l2)
- 若(l1+r)/2<=l2,即[l2,r]本身就是[l1,r]回文串右边的一部分,那么他的贡献在[l1,r]左边已经计算过。
- 如果(l1+r)2/>l2,我们显然可以在[l1,r]回文中心右边找到l2的对称点l2',显然[l2,r]=[l1,l2'],在到达r前,[l2,r]的贡献还是被计算过了。
- 观察到k<=20<26个字母。
- 所以对于每次c[i],我们完全可以凑ccccc(c为字母符号),凑一个贡献加1。
- 对于不用贡献的部分,我们可以凑abcabc。所以,显然我们已开始需要使用abc,才能使得他后面不计贡献,ci>=3,所以可以一开始就使用。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
const int N = 2e6 + 10;
void mysolve()
{
int n,k;
string s="";
cin>>n>>k;
vector<int>x(k+1,0),c(k+1,0);
for(int i=1; i<=k; ++i)cin>>x[i];
bool flag=1;
for(int i=1; i<=k; ++i)
{
cin>>c[i];
if(c[i]-c[i-1]>x[i]-x[i-1]||c[i]>x[i])flag=0;//不合法
}
if(!flag)
{
cout<<"NO"<<endl;
return;
}
string add;
while((int)add.size()<n)add+="abc";
int st=0;
char e='c';
for(int i=1; i<=k; ++i)
{
if(i==1)
{
s+="ab";//先把abc用了,后面凑他就没有贡献
s+=string(c[1]-2,e++);
int len=x[1]-(int)s.size();
s+=add.substr(st,len),st+=len;
continue;
}
s+=string(c[i]-c[i-1],e++);
int len=x[i]-(int)s.size();
s+=add.substr(st,len),st+=len;
}
int len=n-(int)s.size();
s+=add.substr(st,len),st+=len;
cout<<"YES"<<endl;
cout<<s<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}
Problem - E - Codeforces
思路:
- 容易看出可以看成是每个环的异或和,我们只需要讨论一个环的不同长度len的sg值即可
- 发现环切一次就变成链了(笑),所以我们实际只需要计算一条链不同长度的sg值即可。而一个环的长度为len的sg值,就是他第一次切后的所有可能链的sg值的集合的mex,即
- 那怎么求一条链的sg值等价于,显然一条链又可以分成两条,这两条的sg值异或和状态就是这条链可以到达的一个sg值状态。那么这条链的sg值就是
打表出来就很容易观察出每个环长度的sg值
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
const int N = 2e5 + 10;
int n,l,r;
vector<int>edge[N];
bool vis[N];
int dp[N],cnt;
int sg(int x)
{
if(x<=0)return 0;
if(~dp[x])return dp[x];
set<int>s;
for(int i=l; i<=r; ++i)for(int j=0; j<=x-i; ++j)s.insert(sg(j)^sg(x-i-j));//链x的sg值对于他切掉i长度后剩余的两部分j与x-i-j的sg异或和
int ans=0;
while(s.count(ans))ans++;
return dp[x]=ans;
}
void dfs(int u)//dfs搜索一个环的节点数,即长度
{
cnt++;
vis[u]=1;
for(auto v:edge[u])if(!vis[v])dfs(v);
}
void mysolve()
{
//sg打表
// cin>>l>>r;
// memset(dp,-1,sizeof(dp));
// for(int i=1; i<=50; ++i)//求长度为i的环的sg值
// {
// set<int>s;
// for(int j=l; j<=min(r,i); ++j)s.insert(sg(i-j));//即环切掉i长度的所有sg值的mex函数
// int ans=0;
// while(s.count(ans))ans++;
// cout<<ans<<endl;
// }
cin>>n>>l>>r;
for(int i=1; i<=n; ++i)
{
if(i<l||i>(l+r-1))dp[i]=0;//打表出来的sg值规律
else dp[i]=i/l;
}
int x,y;
for(int i=1; i<=n; ++i)cin>>x>>y,edge[x].push_back(y),edge[y].push_back(x);
int ans=0;
for(int i=1; i<=n; ++i)
if(!vis[i])cnt=0,dfs(i),ans^=dp[cnt];//答案就是所有环的异或和
if(ans!=0)cout<<"Alice"<<endl;
else cout<<"Bob"<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
//cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}