贪心。从左到右扫,找到最先出现的 和上个字符相同的 字符(连续的11或00)。从这个字符开始,只要它和上个字符相同,就反转,再往后考察,反转尽量多,直到字符相异时停止。最后统计一下即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char str[100010];
int main(){
int n;
cin>>n;
scanf("%s",str);
bool flag = 0;
for(int i=1;i<n;i++){
if(str[i]==str[i-1]){
if(str[i]=='0')str[i]='1';
else str[i]='0';
flag=1;
}else{
if(flag)break;
}
}
int ans=1;
for(int i=1;i<n;i++){
if(str[i]!=str[i-1]){
ans++;
}
}
cout<<ans<<endl;
return 0;
}
分类讨论k=0,k=1,k>1。当k=0时,f(0)=0,f(x>0)可以是0~p-1任何数,答案就是p^(p-1)。当k=1时,f(x)可以是0~p-1任何数,答案就是p^p。当k>1时,统计有多少个相互制约的循环,也就是有多少组c1*f(x1)=c2*f(x2)=c3*f(x3)=...这种形式,每一组恰好有p个解,假设有cnt组,答案就是p^cnt。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1000000007;
bool vis[1000010];
int main(){
ll p,k;
cin>>p>>k;
ll pp=p;
ll ans=1;
if(k>1){
int cnt=0;
for(int i=1;i<pp;i++){
if(vis[i])continue;
vis[i]=1;
ll cur=i;
while(1){
cur*=k;
cur%=pp;
if(vis[cur])break;
vis[cur]=1;
}
cnt++;
}
while(cnt--){
ans*=pp;
ans%=mod;
}
}else if(k==1){
while(p--){
ans*=pp;
ans%=mod;
}
}else{
p--;
while(p--){
ans*=pp;
ans%=mod;
}
}
cout<<ans<<endl;
return 0;
}
SG函数找规律(还是需要SG函数的方法论指导啊)。分析一下发现,当k是奇数的时候,不管k是几,效果都是一样的,因为这种有向无环图博弈游戏的组合,可以通过SG函数异或得到属于哪种局面;k为偶数的时候同理。只要分别求出两个SG函数,把所有a[i]的SG值异或起来即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int a[100010];
int tab[]={0,1,0,1,2,0,2,0,1,0,1};
int sg(int x){
if(x<=10){
return tab[x];
}else{
if(x&1)return 0;
int tmp=sg(x>>1);
if(tmp==0 || tmp==2)return 1;
else return 2;
}
}
int sgEven(int x){
if(x==0){
return 0;
}else if(x==1){
return 1;
}else if(x==2){
return 2;
}else{
if(x&1){
return 0;
}else{
return 1;
}
}
}
int main(){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int sum=0;
if(k&1){
for(int i=1;i<=n;i++){
sum^=sg(a[i]);
}
}else{
for(int i=1;i<=n;i++){
sum^=sgEven(a[i]);
}
}
if(sum){
cout<<"Kevin"<<endl;
}else{
cout<<"Nicky"<<endl;
}
return 0;
}