Codeforces Round #246 (Div. 2)

来源:互联网 发布:seo基础视频教程 编辑:程序博客网 时间:2024/05/24 06:51
C. Prime Swaps

You have an array a[1], a[2], ..., a[n], containing distinct integers from1 ton. Your task is to sort this array in increasing order with the following operation (you may need to apply it multiple times):

  • choose two indexes, i and j (1 ≤ i < j ≤ n;(j - i + 1) is a prime number);
  • swap the elements on positions i and j; in other words, you are allowed to apply the following sequence of assignments:tmp = a[i], a[i] = a[j], a[j] = tmp (tmp is a temporary variable).

You do not need to minimize the number of used operations. However, you need to make sure that there are at most5n operations.

Input

The first line contains integer n (1 ≤ n ≤ 105). The next line containsn distinct integersa[1], a[2], ..., a[n](1 ≤ a[i] ≤ n).

Output

In the first line, print integer k (0 ≤ k ≤ 5n) — the number of used operations. Next, print the operations. Each operation must be printed as "ij" (1 ≤ i < j ≤ n;(j - i + 1) is a prime).

If there are multiple answers, you can print any of them.

Sample test(s)
Input
33 2 1
Output
11 3
Input
21 2
Output
0
Input
44 2 3 1
Output
32 41 22 4题意:每次交换两个数,要求这两个数的位置差,是素数。思路:根据哥德巴赫猜想,一个合数可以表示成最多5个素数的和,所以j-i+1最多表示成5个素数,保证最多交换5*n次。先打素数表,然后从最小的数字一个个模拟往前放即可,放的时候走的步数直接拆成都是质数即可
#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<map>#include<cmath>#include<algorithm>using namespace std;const int maxn=100010;bool vis[maxn];int n,a[maxn],w[maxn];void init(){    memset(vis,0,sizeof(vis));    int k=sqrt(n);    vis[1]=1;    for(int i=2;i<=k;i++)    {        if(vis[i])continue;        for(int j=i*i;j<=n;j+=i)            vis[j]=1;    }}int main(){        scanf("%d",&n);    init();    for(int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        w[a[i]]=i;    }    int cur=1;    int ans=0;    vector<pair<int,int> > v;    while(cur<=n)    {        while(w[cur]!=cur)        {            for(int j=cur;;j++)            {                if(!vis[w[cur]-j+1])                {                    v.push_back(make_pair(j,w[cur]));                    ans++;                    int tmp=w[cur];                    w[cur]=j;                    w[a[j]]=tmp;                    swap(a[tmp],a[j]);                    break;                }            }        }        cur++;    }    printf("%d\n",ans);    for(int i=0;i<ans;i++)        cout<<v[i].first<<" "<<v[i].second<<endl;    return 0;}

D. Prefixes and Suffixes

You have a string s = s1s2...s|s|, where |s| is the length of string s, and si its i-th character.

Let's introduce several definitions:

  • A substring s[i..j] (1 ≤ i ≤ j ≤ |s|) of string s is string sisi + 1...sj.
  • The prefix of string s of length l (1 ≤ l ≤ |s|) is string s[1..l].
  • The suffix of string s of length l (1 ≤ l ≤ |s|) is string s[|s| - l + 1..|s|].

Your task is, for any prefix of string s which matches a suffix of string s, print the number of times it occurs in string s as a substring.

Input

The single line contains a sequence of characters s1s2...s|s| (1 ≤ |s| ≤ 105) — string s. The string only consists of uppercase English letters.

Output

In the first line, print integer k (0 ≤ k ≤ |s|) — the number of prefixes that match a suffix of string s. Next print k lines, in each line print two integers li ci. Numbers li ci mean that the prefix of the length li matches the suffix of length li and occurs in string s as a substring ci times. Print pairs li ci in the order of increasing li.

Sample test(s)
Input
ABACABA
Output
31 43 27 1
Input
AAA
Output
31 32 23 1
题意:给你一个长度不超过10^5的字符串。要你按长度输出和后缀完全匹配的的前缀的长度。和该前缀在整个串中出现的次数。
思路:我使用扩展KMP做的,先求出next数组,如果next[i]==n-i,则表示前缀有后缀相同,然后输出前缀出线的次数(也可以用next数组得到)

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=100010;char s[maxn];int next[maxn],n;int cnt[maxn],ans[maxn];void getnext(){    n=strlen(s);    next[0]=n;    int j=0;    while(j+1<n&&s[j]==s[j+1])j++;    next[1]=j;    int k=1;    for(int i=2;i<n;i++)    {        int p=k+next[k]-1;        int l=next[i-k];        if(i+l<p+1)next[i]=l;        else        {            j=max(0,p-i+1);            while(i+j<n&&s[i+j]==s[j])j++;            next[i]=j;            k=i;        }    }}int main(){    //freopen("in.txt","r",stdin);    scanf("%s",s);    getnext();    memset(cnt,0,sizeof(cnt));    for(int i=0;i<n;i++)        if(next[i])        cnt[next[i]]++;    int x=cnt[n];    for(int i=n-1;i>=1;i--)//统计长度为i的前缀出现的次数    {        if(cnt[i]==0)continue;        cnt[i]+=x;        x=cnt[i];    }    int num=0;    for(int i=0;i<n;i++)    {        if(next[i]==n-i)ans[num++]=next[i];//判断是不是前缀与后缀相同    }    sort(ans,ans+num);    printf("%d\n",num);    for(int i=0;i<num;i++)    {        printf("%d %d\n",ans[i],cnt[ans[i]]);    }    return 0;}

也可以直接用kmp做,具体详见代码
 
#include<iostream>#include<cstdio>#include<cstring>#define INF 0x3f3f3f3fusing namespace std;const int N = 100005;char s[N];int next[N], n, ans[N], ansn = 0;void get_next(char *seq, int m){    int len=strlen(seq);    next[0]=-1;    int i=0,j=-1;    while(i<n)    {        if(j==-1||seq[i]==seq[j])        {            i++;            j++;            next[i]=j;        }        else j=next[j];    }}int vis[N];int main(){    //freopen("in.txt","r",stdin);    int i = 0;    scanf("%s", s + 1);    n = strlen(s + 1);    get_next(s, n);    int t = next[n];    while (t)    {        ans[ansn++] = t;//next表示适配后应该从那个开始在跟当前位置比较,即前缀有多少长度与当前后缀匹配        t = next[t];    }    for (i = n; i > 0; i--)        vis[next[i]]++;    for (i = n; i > 0; i--)        vis[next[i]] += vis[i];//前缀出线的次数    printf("%d\n", ansn + 1);    for (i = ansn - 1; i >= 0; i--)        printf("%d %d\n", ans[i], vis[ans[i]] + 1);    printf("%d %d\n", n, vis[n] + 1);    return 0;}


0 0
原创粉丝点击