哈理工训练赛2019.3.04

A - Watto and Mechanism

戳我戳我~ 点击打开链接

Watto, the owner of a spare parts store, has recently got an order for the mechanism that can process strings in a certain way. Initially the memory of the mechanism is filled with n strings. Then the mechanism should be able to process queries of the following type: "Given string s, determine if the memory of the mechanism contains string t that consists of the same number of characters as s and differs from s in exactly one position".

Watto has already compiled the mechanism, all that's left is to write a program for it and check it on the data consisting of n initial lines and m queries. He decided to entrust this job to you.

Input

The first line contains two non-negative numbers n and m (0 ≤ n ≤ 3·105, 0 ≤ m ≤ 3·105) — the number of the initial strings and the number of queries, respectively.

Next follow n non-empty strings that are uploaded to the memory of the mechanism.

Next follow m non-empty strings that are the queries to the mechanism.

The total length of lines in the input doesn't exceed 6·105. Each line consists only of letters 'a', 'b', 'c'.

Output

For each query print on a single line "YES" (without the quotes), if the memory of the mechanism contains the required string, otherwise print "NO" (without the quotes).

Examples

Input

2 3
aaaaa
acacaca

aabaa
ccacacc
caaac

Output

YES
NO
NO

题意

给n串模板字符串,再输入m串字符串(所有字符串中,只出现a b c),判断后输入的字符串是否与某个模板串长度相同且只有一个字母不同,若可以则输出Yes,反之输出No。

分析:

我们可以建一个字典树,建树的时候注意要标记每个字符串的结尾(防止结尾问题发生),建好树以后dfs搜索字符串和模板是否对应就ok了。详细看代码注释~

#include <iostream>
using namespace std;
#define ios   ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxn = 3*100000+5;
int tire[maxn][6];
bool End[maxn];
string s;
int n,m;
int tot=1;
bool flag;
int len;
void Insert(string s)//建tire树
{
    int now=0;
    int len=s.length();
    for(int i=0;i<len;i++)
    {
        int id=s[i]-'a';
        if(!tire[now][id])
            tire[now][id]=tot++;
        now=tire[now][id];
    }
    End[now]=true;//模板字符串结尾
}

bool dfs(int pos,int now)//开始搜索
{
    if(pos==len)
    {
        if(End[now]&&!flag)//当长度相等 并且只有一个不同
            return true;
        else
            return false;
    }
    int id=s[pos]-'a';
    for(int i=0;i<3;i++)//只可能出现a,b,c
    {
        if(tire[now][i])
        {
            if(i==id)//字母相同时
            {
                if(dfs(pos+1,tire[now][i]))//继续搜下一个字母
                    return true;
            }
            else if(flag)//字母不同且前面没有不同的字母(这是第一个不同的字母)
            {
                flag=false;//标记有一个字母不同了
                if(dfs(pos+1,tire[now][i]))//继续搜下一个
                    return true;
                flag=true;//回溯
            }
        }
    }
    return false;
}
int main()
{
    ios;
    cin>>n>>m;
    while(n--)
    {
        cin>>s;
        Insert(s);
    }
    while(m--)
    {
        cin>>s;
        flag=true;
        len=s.length();
        if(dfs(0,0))
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
}



B - Infinite Inversions

 戳我呀戳我呀~点击打开链接

There is an infinite sequence consisting of all positive integers in the increasing order: p = {1, 2, 3, ...}. We performed n swap operations with this sequence. A swap(a, b) is an operation of swapping the elements of the sequence on positions aand b. Your task is to find the number of inversions in the resulting sequence, i.e. the number of such index pairs (i, j), that i < j and pi > pj.

Input

The first line contains a single integer n (1 ≤ n ≤ 105) — the number of swapoperations applied to the sequence.

Each of the next n lines contains two integers ai and bi (1 ≤ ai, bi ≤ 109, ai ≠ bi) — the arguments of the swap operation.

Output

Print a single integer — the number of inversions in the resulting sequence.

Examples

Input

2
4 2
1 4

Output

4

Input

3
1 6
3 4
2 5

Output

15

Note

In the first sample the sequence is being modified as follows: . It has 4 inversions formed by index pairs (1, 4), (2, 3), (2, 4) and (3, 4).

题意:

原始序列是1.2.3.4.5.....然后进行n次位置交换,求逆序对数

分析:

不想用归并排序来做,嘤嘤嘤(╥╯^╰╥),氮素,树状数组+离散化 好像还没有懂,等掌握后在来重新补题吧(我太弱惹QAQ)

 

 

C - Pashmak and Parmida's problem

快来戳我呀~ http://codeforces.com/contest/459/problem/D

 

Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants her partner to be clever too (although he's not)! Parmida has prepared the following test problem for Pashmak.

There is a sequence a that consists of n integers a1, a2, ..., an. Let's denote f(l, r, x) the number of indices k such that: l ≤ k ≤ r and ak = x. His task is to calculate the number of pairs of indicies i, j (1 ≤ i < j ≤ n) such that f(1, i, ai) > f(j, n, aj).

Help Pashmak with the test.

Input

The first line of the input contains an integer n(1 ≤ n ≤ 106). The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 109).

Output

Print a single integer — the answer to the problem.

Examples

Input

7
1 2 1 1 2 2 1

Output

8

Input

3
1 1 1

Output

1

Input

5
1 2 3 4 5

Output

0

题意:

F(1,i,a[i])的意思是从1到 i,a[i]的个数 (i从1开始)

例如   1 2 1 1 2 2 1       F(1,4,a[4])=4

那题目的意思就是从1开始到i,a[i]的个数 大于 从j到n a[j]的个数 这样的组合有多少个

分析:

既然分别是从1开始和到n结束,那我们就可以看做是正序和逆序。计算i前面等于a[i]的数的个数,j后面等于a[j]的数的个数,然后比较大小处理,就可以了(i>j)既然要计算前缀和当然就离不开树状数组了(主要是代码少比较好写QAQ)



#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

map<int,int> mp;//key代表a[i],值代表x==a[i]的个数 利用map数出个数
const int maxn=1111111;
int num[maxn];
int L[maxn],R[maxn];//L[i]是左边(也就是前边) x==a[i]的数个数,同理R[i]
int tree[maxn];

int lowbits(int x)
{
    return (x&(-x));
}

void add(int x,int n)
{
    while(x<=n)
    {
        tree[x]++;
        x+=lowbits(x);
    }
}

int sum(int x)
{
    int s=0;
    while(x)
    {
        s+=tree[x];
        x-=lowbits(x);
    }
    return s;
}

int main()
{
    ios;
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>num[i];
        mp[num[i]]++;//num[i]==a[i] 则等于a[i]的个数加一
        L[i]=mp[num[i]];//等于a[i]的个数
    }
    mp.clear();//清空再算右边
    for(int i=n-1;i>=0;i--)
    {
        mp[num[i]]++;
        R[i]=mp[num[i]];
    }

    ll ans=0;
    for(int i=n-1;i>0;i--)
    {
        add(R[i],n);//建树
        ans+=sum(L[i-1]-1);//i<j r[i]->l[i-1] sum1>sum2 所以l[i-1]-1, 若l[i-1] 则sum1>=sum2
    }
    cout<<ans<<endl;
}

D - Balanced Lineup

 这呢这呢~POJ3264 - Balanced Lineup

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers, N and Q
Lines 2.. N+1: Line i+1 contains a single integer that is the height of cow i 
Lines N+2.. NQ+1: Two integers A and B (1 ≤ A≤ B ≤ N), representing the range of cows from Ato B inclusive.

Output

Lines 1.. Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output

6
3
0

题意:

多次询问 求 [l,r] 区间最大值-最小值

分析:

区间最值RQM问题,线段树至今还不会写(嘤嘤嘤,不得不承认我就是个弟弟),然后就用ST来写了(好像是个板子题呢,瑟瑟发抖)

ST算法详情请戳这https://blog.csdn.net/oliver233/article/details/70140319

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int Max[50001][30],Min[50001][30];
int n,m;
void ST(int x)
{

    for(int i=1;i<=x;++i)
    {
        for(int j=1;(1<<i-1)+j<=n;++j)
        {
            Max[j][i]=max(Max[j][i-1],Max[(1<<i-1)+j][i-1]);
            Min[j][i]=min(Min[j][i-1],Min[(1<<i-1)+j][i-1]);
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&Max[i][0]);
            Min[i][0]=Max[i][0];
        }
        int x=(int)(log((double)n)/log(2.0));
        ST(x);
        for(int i=0;i<m;++i)
        {
            int a,b;
		    scanf("%d%d",&a,&b);
            int k=(int)(log((double)(b-a+1))/log(2.0));
            int MAX=max(Max[a][k],Max[b-(1<<k)+1][k]);
            int MIN=min(Min[a][k],Min[b-(1<<k)+1][k]);
            printf("%d\n",MAX-MIN);
        }
    }
}

E - Snowflake Snow Snowflakes

我在这我在这~[POJ 3349]Snowflake Snow Snowflakes[hash]

You may have heard that no two snowflakes are alike. Your task is to write a program to determine whether this is really true. Your program will read information about a collection of snowflakes, and search for a pair that may be identical. Each snowflake has six arms. For each snowflake, your program will be provided with a measurement of the length of each of the six arms. Any pair of snowflakes which have the same lengths of corresponding arms should be flagged by your program as possibly identical.

Input

The first line of input will contain a single integer n, 0 < n ≤ 100000, the number of snowflakes to follow. This will be followed by nlines, each describing a snowflake. Each snowflake will be described by a line containing six integers (each integer is at least 0 and less than 10000000), the lengths of the arms of the snow ake. The lengths of the arms will be given in order around the snowflake (either clockwise or counterclockwise), but they may begin with any of the six arms. For example, the same snowflake could be described as 1 2 3 4 5 6 or 4 3 2 1 6 5.

Output

If all of the snowflakes are distinct, your program should print the message:
No two snowflakes are alike.
If there is a pair of possibly identical snow akes, your program should print the message:
Twin snowflakes found.

Sample Input

2
1 2 3 4 5 6
4 3 2 1 6 5

Sample Output

Twin snowflakes found.

题意:

世界上没有两片雪花是相同的,你信不信,反正我不信。说不定平行时空有呢ヾ(≧O≦)〃嗷~

如果雪花的六瓣长度一样 并且排列顺序一样,则这两片雪花相同,判断有没有相同的雪花

分析:

相同的充要条件是六片长度相同,且排序顺序相同,这里要注意顺时针和逆时针,如果顺时针和逆时针,那反过来就相同辽,

由于长度可能很长,那我们可以用hash来简化,首先判断总长度是否相同,连总长度都不相同肯定就不同惹,如果相同再判断排列是否相对应。

#include<bits/stdc++.h>
using namespace std;
const int Mod=99991;
struct node
{
    int length[15];
    int sum;
};
node a1;
vector<node> v[Mod+1];

bool isEqual(node a,node b)
{
    for(int i=1;i<=6;i++)
    {
        if (a.length[1]==b.length[i]&&a.length[2]==b.length[i+1]&&a.length[3]==b.length[i+2]&&a.length[4]==b.length[i+3]&&a.length[5]==b.length[i+4]&&a.length[6]==b.length[i+5])
		{
			return true;//同向判断
		}
		if (a.length[1]==b.length[i+5]&&a.length[2]==b.length[i+4]&&a.length[3]==b.length[i+3]&&a.length[4]==b.length[i+2]&&a.length[5]==b.length[i+1]&&a.length[6]==b.length[i])
		{
			return true;//逆向判断,反过来相同的情况
		}
    }
    return false;
}



int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        scanf("%d%d%d%d%d%d",&a1.length[1],&a1.length[2],&a1.length[3],&a1.length[4],&a1.length[5],&a1.length[6]);//每一瓣长度
        a1.sum=0;//总长度
        for(int j=1;j<=6;j++)
        {
            a1.length[6+j]=a1.length[j];//因为是成环,所以用两段来便于计算
            a1.sum=(a1.sum+a1.length[j])%Mod;//简单hash一下
        }
        v[a1.sum].push_back(a1);//按总长度进数组
    }
    for(int i=0;i<Mod;i++)
    {
        if(v[i].size()<2)//如果这个总长度的雪花数<2 肯定没有相同的
            continue;
        for(int j=0;j<v[i].size();j++)//如果总长度的雪花数>2,可能有相同的
        {
            for(int k=j+1;k<v[i].size();k++)//这时要比较每个雪花的每个瓣长度的对应位置
            {
                if(isEqual(v[i][j],v[i][k]))//如果有相同的
                {
                    cout<<"Twin snowflakes found."<<endl;
					return 0;
                }
            }
        }
    }
    cout<<"No two snowflakes are alike."<<endl;
}

F - 敌兵布阵

 我在这儿~http://acm.hdu.edu.cn/showproblem.php?pid=1166

C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。 
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:"我知错了。。。"但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的. 

Input

第一行一个整数T,表示有T组数据。 
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。 
接下来每行有一条命令,命令有4种形式: 
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30) 
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30); 
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数; 
(4)End 表示结束,这条命令在每组数据最后出现; 
每组数据最多有40000条命令 

Output

对第i组数据,首先输出“Case i:”和回车, 
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。 

Sample Input

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End 

Sample Output

Case 1:
6
33
59

题意:

如题...???

分析:

单点修改 区间查询 妥妥的树状数组鸭

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxn=50000+5;
int a[maxn],b[maxn];
int n;

int sum(int zz)//求和
{
    int result=0;
    while(zz>0)
    {
        result+=b[zz];
        zz-=zz&-zz;
    }
    return result;
}

void add(int zz,int c)//单点修改
{
    while(zz<=n)
    {
        b[zz]+=c;
        zz+=zz&-zz;
    }
}



int main()
{
	ios;
	int t;
	cin>>t;
	int kase=1,kkase=0;
	while(kase<=t)
	{
        memset(b,0,sizeof b);
		cin>>n;
		int x;
		for(int i=1;i<=n;i++)
		{
			 cin>>x;
	    	 add(i,x);
		}

		while(1)
		{
			if(kase!=kkase)
			{
				cout<<"Case "<<kase<<":"<<endl;
				kkase++;
			}
			string s;
			cin>>s;
			if(s[0]=='E')
				break;
			int x,y;
			cin>>x>>y;
			if(s[0]=='Q')
				cout<<sum(y)-sum(x-1)<<endl;//区间和
			else if(s[0]=='A')
				add(x,y);
			else
				add(x,-y);
   		}
		kase++;
	}
}

G - Oulipo

这儿呢~https://www.sogou.com/link?url=TiECA-reDTArwmdkkjqlMYSupqtafItugdvinVOQKDc.

The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e'. He was a member of the Oulipo group. A quote from the book:

Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…

Perec would probably have scored high (or rather, low) in the following contest. People are asked to write a perhaps even meaningful text on some subject with as few occurrences of a given “word” as possible. Our task is to provide the jury with a program that counts these occurrences, in order to obtain a ranking of the competitors. These competitors often write very long texts with nonsense meaning; a sequence of 500,000 consecutive 'T's is not unusual. And they never use spaces.

So we want to quickly find out how often a word, i.e., a given string, occurs in a text. More formally: given the alphabet {'A', 'B', 'C', …, 'Z'} and two finite strings over that alphabet, a word W and a text T, count the number of occurrences of W in T. All the consecutive characters of W must exactly match consecutive characters of T. Occurrences may overlap.

Input

The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:

  • One line with the word W, a string over {'A', 'B', 'C', …, 'Z'}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W).
  • One line with the text T, a string over {'A', 'B', 'C', …, 'Z'}, with |W| ≤ |T| ≤ 1,000,000.

Output

For every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T.

Sample Input

3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN

Sample Output

1
3
0

题意:

一个字符串在另一个字符串中出现几次

分析:

kmp

#include<iostream>
#include<cstring>
using namespace std;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

char s1[10005],s2[1000000+5];
int next[10005];
int ans;

void prefix_table(char p[])
{
	int len=strlen(p);
	int i,j;
	i=0;j=-1;
	next[0]=-1;
	while(i<len)
	{
		if(j==-1||p[i]==p[j])
		{
			i++;j++;
			next[i]=j;
		}
		else 
			j=next[j];
	}
}

void kmp(char a[],char b[])
{
	int len1=strlen(a),len2=strlen(b);
	int i=0,j=0;
	while(i<len2)
	{
		if(j==-1||a[j]==b[i])
		{
			i++,j++;
			if(j==len1)//次数增加
				ans++;
		}
		else 
			j=next[j];
	}
}
int main()
{
	ios;
	int t;
	cin>>t;
	while(t--)
	{
		cin>>s1>>s2;
		ans=0;
		prefix_table(s1);
		kmp(s1,s2);
		cout<<ans<<endl;
	}
}

H - Power Strings

 题目传送(http://poj.org/problem?id=2406)

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

Input

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output

For each s you should print the largest n such that s = a^n for some string a.

Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3

Hint

This problem has huge input, use scanf instead of cin to avoid time limit exceed.

题意:

求出某字符串最多由几个子串重复组成

分析:

参考了博客上的大佬的文章才知道原来kmp的next数组还能这么玩(๑′ᴗ‵๑),真是太有(can)趣(ren)了!

设Len是s的长度 给出结论:如果len%(len-next[len])==0,则字符串中必存在最小循环节,且循环次数即为 len/(len-next[len])

证明emmmmm 大佬们有好多证明在这我就不证惹

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1000005;
char s[maxn];
int next[maxn];
void prefix_table(char p[])
{
	int len=strlen(p);
	int i,j;
	i=0;j=-1;
	next[0]=-1;
	while(i<len)
	{
		if(j==-1||p[i]==p[j])
		{
			i++;j++;
			next[i]=j;
		}
		else 
			j=next[j];
	}
}

void Count(int len)
{
	if(len%(len-next[len])==0)
           printf("%d\n",len/(len-next[len]));
     else
          printf("1\n");
}

int main()
{
    while(scanf("%s",s)!=EOF)
	{
		if(s[0]=='.') 
			break;
		int len=strlen(s);
		prefix_table(s);
        Count(len);
    }
    return 0;
}

I - Period

 题目请点我 

For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A K,that is A concatenated K times, for some string A. Of course, we also want to know the period K.

Input

The input consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S.The second line contains the string S. The input file ends with a line, having the 
number zero on it.

Output

For each test case, output "Test case #" and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.

Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

题意:

这个题也是找周期,找的是所有循环节可能的周期

分析:

这个题是上个题的变形,把上面的结论扩大到广义上就是前缀为i个字符的串 的 周期=i-next[i]    循环次数=i/周期,   (i % 周期 != 0,不存在周期)。所以就看  i是否被(i-next[i])整除和所得商

#include <iostream>
#include <cstdio>
#include<cstring>
using namespace std;
const int maxn=1000000+5;
char s[maxn];
int next[maxn];
void prefix_table(char p[])
{
	int len=strlen(p);
	int i,j;
	i=0;j=-1;
	next[0]=-1;
	while(i<len)
	{
		if(j==-1||p[i]==p[j])
		{
			i++;j++;
			next[i]=j;
		}
		else 
			j=next[j];
	}
}
void Count(char ss[])
{
	int len=strlen(ss);
	for(int i=0;i<=len;i++)
	{
		if(next[i]==0||next[i]==-1)
			continue;
		if(i%(i-next[i])==0)//有周期
			printf("%d %d\n",i,i/(i-next[i]));
	}
	printf("\n");
}

int main()
{
    int n;
    int kase=0;
    while(scanf("%d",&n)!=EOF)
	{
        if(n==0) 
			break;
        scanf("%s",s);
        prefix_table(s);
        kase++;
        printf("Test case #%d\n",kase);
        Count(s);  
    }
    return 0;
}

J - Hat’s Words

http://acm.hdu.edu.cn/diy/contest_showproblem.php?cid=12654&pid=1002

A hat’s word is a word in the dictionary that is the concatenation of exactly two other words in the dictionary. 
You are to find all the hat’s words in a dictionary. 

Input

Standard input consists of a number of lowercase words, one per line, in alphabetical order. There will be no more than 50,000 words. 
Only one case. 

Output

Your output should contain all the hat’s words, one per line, in alphabetical order.

Sample Input

a
ahat
hat
hatword
hziee
word

Sample Output

ahat
hatword

题意:

找出由两个单词拼接而成的单词

分析:

建立字典树,利用Find方法看是否能找到,注意建树时单词结尾要标记一下,(话说,我因为没标记wa哭惹QAQ)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int const maxn=1e5+10;
int Map[maxn][26];
int sum[maxn];//以某个字符串为前缀的字符串的个数
char a[maxn][105];
bool val[maxn];//标记 一个串的结尾 
int tot=1;//根 
void Insert(char s[])
{
    int now=0;
    for(int i=0;i<strlen(s);i++)
    {
        int c=s[i]-'a';
        if(!Map[now][c])
            Map[now][c]=++tot;
        now=Map[now][c];   
    }
    val[now]=1;//标记 一个串的结尾 
}

bool Find(char s[])
{
    int now=0;
    for(int i=0;i<strlen(s);i++)
    {
         if(Map[now][s[i]-'a']) 
              now=Map[now][s[i]-'a'];
         else
            return 0;
    }
    if(val[now])//前部分是单词才可以(有结尾才是单词)
    	return true;
    else
    	return false;
}

int main()
{
    int num=0;
    char s[110],lpart[110],rpart[110];
    while(~scanf("%s",a[num]))
	    Insert(a[num++]);
    for(int i=0;i<num;i++)
    {
        int len=strlen(a[i]);
        if(len<=1)
            continue;
        for(int j=1;j<len;j++)
        {
            strcpy(lpart,a[i]);//前部分
            strcpy(rpart,a[i]+j);//后部分
            lpart[j]='\0';
            if(Find(lpart)&&Find(rpart))
            {
                printf("%s\n",a[i]);
                    break;
            }
        }
    }
    return 0;
}

也可以用map<string,bool>根据单词前后部分key是否存在来判断 是否可以合成

#include<iostream>
#include<map>
#include<cstring>
using namespace std;

map <string,bool> M;
string S[50044];
int main()
{
    int num=0;
    string s;
    while(cin>>s)
    {
        S[num++]=s;//单词为key
        M[s]=true;//存在
    }

    string s1,s2;
    int len;
    for(int i=0;i<num;i++)
    {
	    s=S[i];
		len=S[i].length();
        for(int j=0;j<len;j++)
        {
            s1=s.substr(0,j);//前部分
            s2=s.substr(j);//后部分

            if(M[s1]&&M[s2])//两个单词存在
            {
                cout<<S[i]<<endl;
                break;
            }
        }
    }
}

K - Black Box

 http://poj.org/problem?id=1442

Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empty and i equals 0. This Black Box processes a sequence of commands (transactions). There are two types of transactions: 

ADD (x): put element x into Black Box; 
GET: increase i by 1 and give an i-minimum out of all integers containing in the Black Box. Keep in mind that i-minimum is a number located at i-th place after Black Box elements sorting by non- descending. 

Let us examine a possible sequence of 11 transactions: 

Example 1 

N Transaction i Black Box contents after transaction Answer 

      (elements are arranged by non-descending)   

1 ADD(3)      0 3   

2 GET         1 3                                    3 

3 ADD(1)      1 1, 3   

4 GET         2 1, 3                                 3 

5 ADD(-4)     2 -4, 1, 3   

6 ADD(2)      2 -4, 1, 2, 3   

7 ADD(8)      2 -4, 1, 2, 3, 8   

8 ADD(-1000)  2 -1000, -4, 1, 2, 3, 8   

9 GET         3 -1000, -4, 1, 2, 3, 8                1 

10 GET        4 -1000, -4, 1, 2, 3, 8                2 

11 ADD(2)     4 -1000, -4, 1, 2, 2, 3, 8   


It is required to work out an efficient algorithm which treats a given sequence of transactions. The maximum number of ADD and GET transactions: 30000 of each type. 


Let us describe the sequence of transactions by two integer arrays: 


1. A(1), A(2), ..., A(M): a sequence of elements which are being included into Black Box. A values are integers not exceeding 2 000 000 000 by their absolute value, M <= 30000. For the Example we have A=(3, 1, -4, 2, 8, -1000, 2). 

2. u(1), u(2), ..., u(N): a sequence setting a number of elements which are being included into Black Box at the moment of first, second, ... and N-transaction GET. For the Example we have u=(1, 2, 6, 6). 

The Black Box algorithm supposes that natural number sequence u(1), u(2), ..., u(N) is sorted in non-descending order, N <= M and for each p (1 <= p <= N) an inequality p <= u(p) <= M is valid. It follows from the fact that for the p-element of our u sequence we perform a GET transaction giving p-minimum number from our A(1), A(2), ..., A(u(p)) sequence. 
 

Input

Input contains (in given order): M, N, A(1), A(2), ..., A(M), u(1), u(2), ..., u(N). All numbers are divided by spaces and (or) carriage return characters.

Output

Write to the output Black Box answers sequence for a given sequence of transactions, one number each line.

Sample Input

7 4
3 1 -4 2 8 -1000 2
1 2 6 6

Sample Output

3
3
1
2

题意:

输入n,m代表数个数和查询次数。其中查询方法是在前m[i]中第i小的是哪个,比如样例,1.2.6.6 在前1个数中,第一小的是3,前2个数中,第2小的是3,前6个数中,第3小的是1,前6个数中第4小的是2.

分析:

使用大根堆和小根堆。其中,对于序列S[1..n],及表示迭代器位置的index,大顶堆维护排序后的S[1..index-1],小顶堆维护排序后的S[index..n], 例如S[1..n] = 1,2,3,4,5,6,7,index = 4,则大根堆为{1,2,3},小根堆为{4,5,6,7}。为什么要这样维护呢?因为当小堆最小的元素都大于大堆最大的元素时,那么序列中排第index个数就是小堆最小的数了。

#include<iostream>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> > small;
priority_queue<int ,vector<int>,less<int> > big;
const int maxn=30000+5;
int a[maxn];

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
        cin>>a[i];
    int k,now=0;
    for(int i=0;i<m;i++)
    {
        cin>>k;
        while(now<k)
        {
            small.push(a[now]);
            if(!big.empty()&&big.top()>small.top())//当大根堆的堆顶(也就是大根堆最大的数)>小根堆的堆顶(小根堆最小的数)
            {                                      //破坏了小堆最小的元素都大于大堆最大的元素,开始维护
                int s1=big.top();
                int s2=small.top();
                big.pop();
                small.pop();
                small.push(s1);
                big.push(s2);
            }
            now++;
        }
        cout<<small.top()<<endl;
        big.push(small.top());
        small.pop();
    }
}
#include<bits/stdc++.h>//输到第x个时第i小是多少
//#include<iostream>
//#include<queue>
//using namespace std;
//const int maxn=30000+5;
//priority_queue<int, vector<int>, greater<int> >pq;
//int a[maxn],b[maxn];
//int main()
//{
//    int n,m;
//    cin>>n>>m;
//    for(int i=1;i<=n;i++)
//        cin>>a[i];
//
//    for(int i=1;i<=m;i++)
//    {
//        cin>>b[i];
//        for(int j=1;j<=b[i];j++)
//        {
//            pq.push(a[j]);
//        }
//        for(int j=1;j<=i;j++)
//        {
//            if(j==i)
//                cout<<pq.top()<<endl;
//            pq.pop();
//        }
//    }
//}

#include<iostream>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> > small;
priority_queue<int ,vector<int>,less<int> > big;
const int maxn=30000+5;
int a[maxn];

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
        cin>>a[i];
    int k,now=0;
    for(int i=0;i<m;i++)
    {
        cin>>k;
        while(now<k)
        {
            small.push(a[now]);
            if(!big.empty()&&big.top()>small.top())//当大根堆的堆顶(也就是大根堆最大的数)>小根堆的堆顶(小根堆最小的数)
            {                                      //破坏了小堆最小的元素都大于大堆最大的元素,开始维护
                int s1=big.top();
                int s2=small.top();
                big.pop();
                small.pop();
                small.push(s1);
                big.push(s2);
            }
            now++;
        }
        cout<<small.top()<<endl;
        big.push(small.top());
        small.pop();
    }
}

L - 合并果子

https://www.luogu.org/problemnew/show/P1090

   果园里面有n堆果子,每堆果子有xi个,每个果子的重量为1,小明每次把i,j两堆果子移成一堆,需要花费的体力为xi+xj。最后移成一堆,求最小花费体力值。
其中1<=n<=10000,1<=m<=10000。均为正整数。

Input

    每组数据第一行输入一个正整数n,表示有n堆果子。

    接下来一行有n个正整数,表示每堆果子的重量。

    输入以EOF结尾。

Output

    每组数据单独一行,输出所花费的最小体力值。

Sample Input

3

1 2 9

5

1 3 9 18 30

Sample Output

15

109

这个经典题,贪心也可以,优先队列也可以(感jio大家应该都做过(逃 ʕ•̫͡•ʕ̫͡ʕ•͓͡•ʔ-̫͡-ʕ•̫͡•ʔ̫͡ʔ-̫͡-ʔ

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
int main(){
int n;
int a[10010];
ll sum;
while(cin>>n)
{
int k=n;
ll min=0;
priority_queue<int,vector<int>,greater<int> > pq;
for(int i=0;i<n;i++)
    cin>>a[i];
for(int i=0;i<n;i++)
    pq.push(a[i]);
while(!pq.empty())
    {
        int T=2;
        sum=0;
        while(T--)
        {
            sum+=pq.top();
            pq.pop();
        }
        min+=sum;
        pq.push(sum);
        if(pq.size()==1)
            break;
    }
    cout<<min<<endl;
}
    return 0;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值