您的位置:首页 > 其它

Codeforces Round #246 (Div. 2)

2014-06-20 17:34 211 查看
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
3
3 2 1


Output
1
1 3


Input
2
1 2


Output
0


Input
4
4 2 3 1


Output
3
2 4
1 2
2 4


题意:每次交换两个数,要求这两个数的位置差,是素数。
思路:根据哥德巴赫猜想,一个合数可以表示成最多5个素数的和,所以j-i+1最多表示成5个素数,保证最多交换5*n次。先打素数表,然后从最小的数字一个个模拟往前放即可,放的时候走的步数直接拆成都是质数即可。
[code]#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.
InputThe single line contains a sequence of characters s1s2...s|s| (1 ≤ |s| ≤ 105) — string s. The string only consists of uppercase English letters.
OutputIn 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
3
1 4
3 2
7 1
Input
AAA
Output
3
1 3
2 2
3 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
;
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;
}
[/code]
也可以直接用kmp做,具体详见代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 100005;
char s
;
int next
, n, ans
, 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
;

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
;
    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
 + 1);
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: