Codeforces gym 2013-2014 Samara SAU ACM ICPC Quarterfinal Qualification Contest

本文深入探讨了CodeForces竞赛中的高效算法应用,包括解决力量与黑暗面、相似字符串匹配等核心问题。通过前缀最大和后缀最大值的利用,优化了解决策略,实现了时间复杂度的大幅降低。此外,还介绍了如何使用哈希映射和三维数组的一维化技巧,以高效解决相似字符串判断问题。最后,详细讲解了通过前缀和方法快速求解连续子集和问题,以及利用二进制位操作解决秘密信息修改问题,展示了算法在实际编程挑战中的强大威力。

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

题目地址:http://codeforces.com/gym/100247


2014.10.27版

26号训练的题,今天发现A题有更高效的解法,用到了前缀最大值和后缀最大值


A. The Power of the Dark Side
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

On the Jedi Tournament n Jedi are battling each other. Every Jedi has three parameters: strength, agility and intelligence. All parameters of all Jedi are different. When two Jedi have a fight, the winner will be the Jedi which has more parameters higher compared to the same parameters of his opponent. For example, Jedi with parameters (5, 9, 10) defeats Jedi with parameters (2, 12, 4) because of first and third parameters.

Sith have a plan to turn one the Jedi to the dark side of the Force. It will give him a powerful skill that allows to swap some his parameters, maybe more than one time, before every fight. Sith wish their new apprentice to defeat all of the remaining Jedi.

Which Jedi can be used by Sith to lead their plan to success?

Input

The first line contains the only integer n (1 ≤ n ≤ 200000) — the number of the Jedi.

Then n lines follow. Each of them contains three integers separated by space: aibi and ci (1 ≤ ai, bi, ci ≤ 109) — the parameters of the Jedi.

All aibi and ci are pairwise distinct.

Output

In the first line output one integer m — the number of the suitable Jedi.

In the second line output m integers — the numbers of these Jedi — in the ascending order.

Sample test(s)
input
4
5 9 10
2 12 4
8 7 3
6 11 1
output
2
1 4
input
4
4 1 11
5 8 9
2 12 6
7 3 10
output
3
2 3 4


先讲最优的算法O(n)解决的

每次读入的时候调整,保证ai<bi<ci

记录下这个人前面的所有人ai的最大值,bi的最大值,ci的最大值,我把它成为前缀最大值

同样,记录后缀最大值

这个人如果符合题意当且仅当

他的最大值ci 大于从头到上一个人的bi 前缀最大值 且 大于从尾到后一个人的bi 后缀最大值

他的次大值bi 大于从头到上一个人的ai 前缀最大值 且 大于从尾到后一个人的ai 后缀最大值

代码如下:

//Hello. I'm Peter
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN
#define N 200100
#define M
int n,a,b,c;
struct Digit
{
    int a,b,c;
}d[N];
int prefixmax[N][3];
int suffixmax[N][3];
int order[10],num_ans,ans[N];
int main()
{
    cin>>n;
    repin(i,1,n){
        scanf("%d %d %d",&a,&b,&c);
        order[1]=a,order[2]=b,order[3]=c;
        sort(order+1,order+1+3);
        d[i].a=order[1];
        d[i].b=order[2];
        d[i].c=order[3];
    }
    repin(i,1,n){
        prefixmax[i][0]=max(prefixmax[i-1][0],d[i].a);
        prefixmax[i][1]=max(prefixmax[i-1][1],d[i].b);
        prefixmax[i][2]=max(prefixmax[i-1][2],d[i].c);
    }
    depin(i,n,1){
        suffixmax[i][0]=max(suffixmax[i+1][0],d[i].a);
        suffixmax[i][1]=max(suffixmax[i+1][1],d[i].b);
        suffixmax[i][2]=max(suffixmax[i+1][2],d[i].c);
    }
    num_ans=0;
    repin(i,1,n){
        if(d[i].c>prefixmax[i-1][1] && d[i].b>prefixmax[i-1][0]){
            if(d[i].c>suffixmax[i+1][1] && d[i].b>suffixmax[i+1][0]){
                ans[++num_ans]=i;
            }
        }
    }
    cout<<num_ans<<endl;
    bool first=true;
    repin(i,1,num_ans){
        if(first) first=false;
        else printf(" ");
        printf("%d",ans[i]);
    }
    printf("\n");
}


下面这个方法复杂度是O(nlogn)的,虽然复杂度高了,的确没有上一个高效,而且空间耗费也大

但是,这个方法用到了一个三维变成一维的办法,有助于算法思想提高。

还有,感谢鬼子王提供这个思路给我0.0


把三维的变成一维的,最多有6*10^5这么多个数,然后从小到大排序,题目保证了每个数两两不同

当然,是对结构体数组排序,结构体存储这个数,这个数对应的哪个人

同时,存储两个变量

一个是,从1到此,出现次数>=1有多少人

一个是,从1到此,出现次数>=2有多少人

由于一个人有3个变量,所有出现次数最多为3,且一定会有3。

当碰到出现次数为3时,查找之前记录下的此人在出现次数为2时的位置

如果3这个位置之前出现次数>=2的人数为n 且 2那个位置之前出现次数>=1的人数也为n,这个人就是符合题意的人

扫一遍,调用2个map,就可以知道符合题意的人分别是谁了


代码如下:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define MAXN 600100
#define N 200100
struct Digit
{
    int id,x;
    int num1,num2;
}d[MAXN];
bool comp(const Digit a,const Digit b){
    return a.x<b.x;
}
int ans[N],num_ans;
int num_d;
int num1,num2,n,a,b,c;
map<int,int>apptime;
map<int,int>sp;
int main()
{
    cin>>n;
    int num_d=0,t;
    repin(i,1,n){
        scanf("%d %d %d",&a,&b,&c);
        t=++num_d;
        d[t].id=i;
        d[t].x=a;
        t=++num_d;
        d[t].id=i;
        d[t].x=b;
        t=++num_d;
        d[t].id=i;
        d[t].x=c;
    }
    sort(d+1,d+1+num_d,comp);
    num1=num2=0;
    apptime.clear(),sp.clear();
    num_ans=0;
    repin(i,1,num_d){
        t=apptime[d[i].id];
        t+=1;
        if(t==3){
            int w=sp[d[i].id];
            if(d[w].num1==n && num2==n){
                int t=++num_ans;
                ans[t]=d[i].id;
            }
        }
        else{
            if(t==1) num1+=1;
            else if(t==2){
                num2+=1;
                sp[d[i].id]=i;
            }
            apptime[d[i].id]=t;
            d[i].num1=num1;
            d[i].num2=num2;
        }
    }
    if(num_ans!=0) sort(ans+1,ans+1+num_ans);
    printf("%d\n",num_ans);
    bool first=true;
    repin(i,1,num_ans){
        if(first) first=false;
        else printf(" ");
        printf("%d",ans[i]);
    }
    printf("\n");
}


B. Similar Strings
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Let's call two strings similar if there exists a bijective mapping over characters, which, when applied to the characters of the first string, makes it equal to the second string. For example, «abacaba» and «tetatet» are similar strings, but «test» and «bear» — are not. Given the set of strings, find the number of pairs of similar strings.

Input

The first line contains one integer n — the number of strings.

Next n lines contain non-empty strings of lowercase Latin letters. The sum of lengths of these strings does not exceed 106.

Output

Output the only integer —the number of pairs of similar strings.

Sample test(s)
input
4
abacaba
tetatet
test
bear
output
1
input
4
jury
code
will
pass
output
2
input
4
your
code
wont
pass
output
3


这题,用一个map<vector<int>,int>m; 记录

vector 存储的是这个字符串每个字母出现的早晚,用数字表示

比如abcabcdea

a是第一个出现的,就为0,b为1,c为2,d为3 e为4

则对应的vector应为 0  1  2  0  1  2  3  4  0

由于字母是'a'-'z',vector里的数不会超过25

vector就是一种hash方式,正确的讲所有同种类型的串 映射 到一个vector上,而map的second值表示这个vector出现了多少次

这样子每个串在map中查找,维护ans,并且再更新map,复杂度为O(nlogn)的方法,就可以得到答案了

代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 1001000
#define N
#define M
int idx(char c){
    return c-'a';
}
char s[MAXN];
int n,num,apptime[30];
map<vector<int>,ll>m;
ll ans;
int main()
{
//    input;
    cin>>n;
    ans=0;
    repin(i,1,n){
        scanf("%s",s);
        int len=len(s);
        repin(i,0,25){
            apptime[i]=0;
        }
        num=0;
        vector<int>v;
        v.clear();
        rep(j,0,len){
            int c=idx(s[j]);
            int t;
            if(apptime[c]==0){
                t=apptime[c]=++num;
            }
            else t=apptime[c];
            v.pb(t);
        }
        ans+=m[v];
        m[v]+=1;
    }
    cout<<ans<<endl;
}


C. Victor's Research
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Unacknowledged scientist Victor conducts a pseudoscientific research of the relation between integers that cross his mind and the integer that comes into his assistant's mind. He wrote the integers a1...an which had crossed his mind. Then it turned up that the integer s had come into his assistant's mind. Victor wants to determine how many consecutive non-empty sets of integers alal + 1...ar(l ≤ r) have the sum al + al + 1 + ... + ar = s.

Input

The first line contains two integers separated by space: n and s (1 ≤ n ≤ 200000 - 2·1014 ≤ s ≤ 2·1014) — the number of integers which crossed Victor's mind and the integer that came into his assistant's mind.

The second line contains n integers separated by space: ai ( - 109 ≤ ai ≤ 109) — the integers which crossed Victor's mind.

Output

Output the only integer — the number of consecutive non-empty sets of integers which have the sum s.

Sample test(s)
input
5 2
-1 1 2 -1 1
output
5
input
6 3
3 -2 1 -1 1 2
output
3

这题很简单

维护一个前缀和,dp一下就行了

今天朋友终于明白这个方法名字叫“前缀和”,还有朋友争论了很久0.0,其实我早就会了,没想到它有这么高冷的名字

顺便说下,前缀和方法在cf里频繁出现,尤其是div2 c题

代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 1001000
#define N
#define M
int n;
ll s,t,ans,sum,t1;
map<ll,ll>m;
int main()
{
//    input;
    m.clear();
    cin>>n>>s;
    ans=sum=0;
    repin(i,1,n){
        scanf("%lld",&t);
        sum+=t;
        t1=sum-s;
        ans+=m[t1];
        m[sum]+=1;
        if(sum==s) ans+=1;
    }
    cout<<ans<<endl;
}


H. Secret Information
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Little known hacker Heaven just got access to the secret information about problems of some major programming contest. He wants to change statement of one of the problems to sabotage the contest.

For Heaven, initial and target statements are just strings of zeroes and ones. He can take any substring of initial statement and negate it — replace each zero with one, and each one with zero.

Heaven would like to leave no trace of his actions, so he wants to minimize the number of steps in turning initial statement to target.

Input

The first line contains one integer n (1 ≤ n ≤ 200000) — the length of the strings.

Then two strings of «0» and «1» follow — the binary codes of initial and target statement.

Output

Output one integer — the minimal possible number of steps.

Sample test(s)
input
6
101010
110011
output
2
input
7
1010101
0011100
output
3

这题我就不讲了,谁都会做,签到题


//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 200100
#define N
#define M
int n,ans;
bool start;
char s1[MAXN],s2[MAXN];
int main()
{
//    input;
    cin>>n;
    scanf("%s %s",s1,s2);
    ans=0;
    start=false;
    rep(i,0,n){
        if(s1[i]==s2[i]){
            if(!start) continue;
            else{
                ans+=1;
                start=false;
            }
        }
        else{
            if(!start) start=true;
        }
    }
    if(start) ans+=1;
    cout<<ans<<endl;
}


D. Hamming Distance
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Once the boy named Richard received the cat as a gift. Of course, he immediately started to think up how to name him. Three his friends offered their variants: strings ab and c of equal lengths n. Richard notes the distance  between strings s1 and s2 as a number of positions in which the characters in these strings differ. For example, . Richard wants to please his friends and name the cat such the name s that  is minimal.

Input

The first line contains one integer n (1 ≤ n ≤ 200000) — the length of the strings.

Then three strings ab и c of the same length n follow — the names offered by Richard's friends. The strings consist of the lowercase Latin letters.

Output

Output the only string of the length n, consisting of the lowercase Latin letters — the name for the cat. If there are many possible names satisfying the condition, output any of them.

Sample test(s)
input
6
needle
turkey
bottle
output
turtle

很简单

每一列3个元素

如果都相同,输出,此时单列p值为0

如果都不同,输出第一个,此时单列p值为2

如果存在两个相同,输出相同的,此时单列p值为1

代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 200100
#define N
#define M
int n;
char s[3][MAXN];
char c1,c2,c3;
int main()
{
//    input;
    cin>>n;
    scanf("%s %s %s",s[0],s[1],s[2]);
    rep(i,0,n){
        c1=s[0][i],c2=s[1][i],c3=s[2][i];
        if(c1==c2 && c2==c3) printf("%c",c1);
        else if(c1!=c2 && c1!=c3 && c2!=c3) printf("%c",c1);
        else if(c1==c2) printf("%c",c1);
        else if(c2==c3) printf("%c",c2);
        else if(c1==c3) printf("%c",c1);
    }
    printf("\n");
}




想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值