首页 > 代码库 > cf Round 603

cf Round 603

A.Alternative Thinking(思维)

给出一个01串,你可以取反其中一个连续子串,问取反后的01子串的最长非连续010101串的长度是多少。

我们随便翻一个连续子串,显然翻完之后,对于这个连续子串而言,最后的答案一定不会变优。
只会对你翻的左端点和右端点相邻的数字产生贡献。我们计左端点为l,右端点为r。
而且要想最大化贡献,必须要使得这个a[l]和a[l-1]一样。a[r]和a[r+1]一样。
那么我们只要找到可以使这个贡献获得最大时的条件就行了。

技术分享
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
# define fi first
# define se second
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==-) flag=1;
    else if(ch>=0&&ch<=9) res=ch-0;
    while((ch=getchar())>=0&&ch<=9)  res=res*10+(ch-0);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(-); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+0);
}
const int N=100005;
char s[N];

int main ()
{
    int n, cnt=0, ans1=0, ans2=0;
    char f= ;
    scanf("%d%s",&n,s+1);
    FOR(i,1,n) {
        if (s[i]==1) ans2=ans1+1;
        else ans1=ans2+1;
        if (f==s[i]) cnt++;
        f=s[i];
    }
    int ans=max(ans1,ans2);
    if (cnt==1) ans+=1;
    else if (cnt>=2) ans+=2;
    printf("%d\n",ans);
    return 0;
}
View Code

 

B.Moodular Arithmetic(数论)

告诉你p和k,其中(0<=k<=p-1),x属于{0,1,2,3,....,p-1},f函数要满足f(k*x%p)=k*f(x)%p,f(x)的范围必须在[0,p-1]内,问这样的f函数有多少个

先观察小情形。
k=0时,此时有f(0)=0.即除了0其他可以随便乱取。那么我们得到ans=p^(p-1).
k=1时,此时有f(x)=f(x).此时随便乱取。那么我们得到ans=p^p.
后面我们发现就不好办了。
但是我们发现f(k*k*x)=k*f(k*x)%p=k*(k*f(x)%p)%p.
这不是乘法取模吗。那么则有f(k^n*x%p)=(k^n)%p*f(x)%p.
我们要是能使k^n%p=1就好了,那么就会有n个数在一个环上面。我们令n最小。
那么n就是k关于p的一个阶。
因为f(0)=0,那么答案就是p^((p-1)/n).

技术分享
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
# define fi first
# define se second
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==-) flag=1;
    else if(ch>=0&&ch<=9) res=ch-0;
    while((ch=getchar())>=0&&ch<=9)  res=res*10+(ch-0);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(-); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+0);
}
const int N=100005;

LL muti_mod(LL a,LL b,LL c)
{
    a%=c; b%=c;
    LL ret=0;
    while (b) {
        if (b&1){ret+=a; if (ret>=c) ret-=c;}
        a<<=1;
        if (a>=c) a-=c;
        b>>=1;
    }
    return ret;
}
LL pow_mod(LL x,LL n,LL mod)
{
    if (n==1) return x%mod;
    int bit[64], k=0;
    while (n) bit[k++]=n&1, n>>=1;
    LL ret=1;
    for (k=k-1; k>=0; --k){
        ret=muti_mod(ret,ret,mod);
        if (bit[k]==1) ret=muti_mod(ret,x,mod);
    }
    return ret;
}
int eul(LL p, LL k)
{
    FO(i,2,p) if ((p-1)%i==0&&pow_mod(k,(LL)i,p)==1) return i;
}
int main ()
{
    LL p, k;
    scanf("%lld%lld",&p,&k);
    if (k==0) printf("%lld\n",pow_mod(p,p-1,MOD));
    else if (k==1) printf("%lld\n",pow_mod(p,p,MOD));
    else {
        int temp=eul(p,k);
        printf("%lld\n",pow_mod(p,(p-1)/temp,MOD));
    }
    return 0;
}
View Code

 

C.Lieges of Legendre(SG函数)

变形版nim游戏,操作有两个,1.取出一个石子。2.把一堆偶数个石子变成k堆偶数/2个石子。

分析:
抽象成DAG,这个DAG的顶点度数最大为2,打sg表找规律。
发现k为偶数时很简单。 k为奇数时。模拟求sg函数,可以递归的求出sg。
复杂度O(n*logai).

技术分享
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
# define fi first
# define se second
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==-) flag=1;
    else if(ch>=0&&ch<=9) res=ch-0;
    while((ch=getchar())>=0&&ch<=9)  res=res*10+(ch-0);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(-); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+0);
}
const int N=100005;

int n, k, a[7]={0,1,0,1,2,0,2};

int find(int x)
{
    if (k%2==0) {
        if (x<=2) return x;
        else return x%2==0;
    }
    else {
        if (x<=6) return a[x];
        if (x&1) return 0;
        else {
            if (find(x/2)==1) return 2;
            else return 1;
        }
    }
}
int main ()
{
    int temp, ans=0;
    scanf("%d%d",&n,&k);
    while (n--) scanf("%d",&temp), ans^=find(temp);
    puts(ans?"Kevin":"Nicky");
}
View Code

 

D.Ruminations on Ruminants(数学)

枚举出三个点之后判定是否过原点还是可以的.但是不能枚举.
只知道相加180这个限制是不好想办法的.
所以转化成:远点向直线做垂线,只有三个垂足在同一条直线上的时候,才行.
那么我们先做找出来垂足,然后数三个点在一条直线的三元组个数.
转化一下,就是两点确定一条直线,然后再看每一条直线上有多少个点,用组合数算.
但是这样不好写(还要转成直线的方程),i j k(i < j < k), 我们枚举i,要求j和k相对于i的斜率必须一样. 如果有重合的点,那么任意一个第三个点都可以.
注意,要全部用整数,先联立方程算出来垂足,用分子分母表示,然后求斜率减之后也化成标准的形式.

技术分享
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>

using namespace std;

typedef long long ll;

const int maxn = 2000 + 100;
int n, a[maxn], b[maxn], c[maxn], ac[maxn], bc[maxn], a2b2[maxn];
ll res;
struct Point {
    ll x, y;
};

ll gcd(ll x, ll y) {
    if(y == 0)
    return x;
    return gcd(y, x % y);
}
Point getStand(Point t) {
    if(t.x == 0) {
    if(t.y == 0)
        return t;
    t.y = 1;
    return t;
    }
    else if(t.y == 0) {
    t.x = 1;
    return t;
    }
    ll d = gcd(abs(t.x), abs(t.y));
    t.x /= d;
    t.y /= d;
    if(t.x < 0 && t.y < 0 || t.x > 0 && t.y < 0) {
    t.x = -t.x;
    t.y = -t.y;
    }
    return t;
}
void solve() {
    for(int i = 1; i <= n; i++) {
    ac[i] = a[i] * c[i];
    bc[i] = b[i] * c[i];
    a2b2[i] = a[i] * a[i] + b[i] * b[i];
    }
    res = 0;
    for(int i = 1; i <= n; i++) {
    map<ll, map<ll, ll> > mp;
    int same = 0, ans = 0;
    for(int j = i + 1; j <= n; j++) {
        Point t;
        t.x = (ll)a2b2[j] * (ll)ac[i] - (ll)a2b2[i] * (ll)ac[j];
        t.y = (ll)a2b2[j] * (ll)bc[i] - (ll)a2b2[i] * (ll)bc[j];
        t = getStand(t);
        if(t.x == 0 && t.y == 0) {
        same++;
        ans += (j - i - 1);
        }
        else {
        ans += mp[t.x][t.y] + same;
        mp[t.x][t.y]++;
        }
    }
    res += ans;
    }
    printf("%I64d\n", res);
}

int main() {
  //  freopen("D.txt", "r", stdin);
    while(scanf("%d", &n) != EOF) {
    for(int i = 1; i <= n; i++) {
        scanf("%d%d%d", &a[i], &b[i], &c[i]);
    }
    solve();
    }
    return 0;
}
View Code

 

E.Pastoral Oddities(待填坑)

cf Round 603