C题意:

给定n个点(标号0~n-1)的度数(就是与其邻接的点的个数)和所有与它邻接的点标号的异或和,求满足这些条件的树的边应该是怎么连的,将边输出出来

这里可以理解成拓扑排序的方式考虑,当i度数为1的时候,那么我们必然知道 i 肯定得与s[i]相连使其剩余的异或值为0

所以建立一个队列不断将度数变为1的点放进来,得到边以后,不断更新点的度数和其对应的异或和的值

 #include <bits/stdc++.h>

 using namespace std;
const int N = (<<);
int n,degree[N] , s[N] , vis[N];
#define pii pair<int,int>
vector<pii> v;
queue<int> q;
int main()
{
// freopen("a.in" , "r" , stdin);
scanf("%d" , &n);
for(int i= ; i<n ; i++){
scanf("%d%d" , &degree[i] , &s[i]);
if(degree[i]==) q.push(i);
}
while(!q.empty()){
int u = q.front();
q.pop();
// cout<<u<<" "<<degree[u]<<" "<<s[u]<<endl;
if(degree[u]==) continue;
degree[u]--;
if(!vis[s[u]]){
degree[s[u]]-- , s[s[u]]^=u;
if(degree[s[u]]==) q.push(s[u]) , vis[s[u]]=;
}
else degree[s[u]]--;
v.push_back(make_pair(u , s[u]));
}
printf("%d\n" , v.size());
for(int i= ; i<v.size() ; i++)
printf("%d %d\n" , v[i].first , v[i].second);
return ;
}

cf 501C

D题意:

给定两个0~n-1的排列方式,像康托展开式那种方式计算对应排名(从0开始,也就是说排名可能是0~n!)

将两种排列的排名相加后计算新的排名%n!后的对应的排列方式

这里我们可以计算排列上每一位对应的名次,这个名次的含义是从最高位开始这个数在不曾出现的数字中的排名,这个排名可以用树状数组解决

如序列 2 1 3 0 4 对应排名 2 1 2 0 0

这里给定样例

5

2 1 3 0 4

2 0 4 3 1

可以看出来两个序列排名后是:

2 1 1 0 0

2 0 2 1 0

相当于把每一位相加就说明得到新排名是符合总和相加所得排名的(不懂可以学一下康拓展开)

就是4 1 3 1 0

那这里对应每一位来说,都不应该出现超出当前位所能承受的排名就进位,比如这里3的位置最多排名应该为2,所以变成3%3=0,前面进位1+1=2

新的排名是4 2 0 1 0

根据新的排名倒过来算出每一位上的数字,我用的是线段树处理,当然应该有更好的办法,只是我比较弱~

 #include <bits/stdc++.h>

 using namespace std;
const int N = ;
int n , a[N] , cnt[N] , use[N] , use1[N];
#define ll long long
ll ans;
int main()
{
// freopen("a.in" , "r" , stdin);
scanf("%d" , &n);
for(int i= ; i<=n ; i++){
scanf("%d" , &a[i]);
cnt[a[i]]++;
} int odd = ;
for(int i= ; i<=n ; i++){
if(cnt[i]&) odd++;
}
if(((n&)== && odd) || ((n&)&&odd>)){
puts("");
return ;
}
//从左右两端出发能匹配到的最大次数
int maxMatch = ;
for(int i=,j=n ; i<=j ; i++,j--){
if(a[i]==a[j])maxMatch++;
else break;
}
if(maxMatch==(n+)/){
printf("%I64d\n" , (ll)n*(n+)/);
return ;
}
//从中间出发能匹配到的最大次数
int maxMid = ;
for(int i=n/ , j=(n+)/+; i> ; i-- , j++){
if(a[i]==a[j])maxMid++;
else break;
}
ans = ; //计算最右侧出发还存在值的最大位置
int mxRg = ;
for(mxRg= ; mxRg<=n ; mxRg++){
if(n& && mxRg==(n+)/ && cnt[a[mxRg]]&) continue;
else if(n& && mxRg==(n+)/) break;
if(mxRg<=(n+)/){
if(use1[a[mxRg]]+<=cnt[a[mxRg]]/) {use1[a[mxRg]]++;continue;}
else break;
}
else {
if(a[mxRg]==a[n-mxRg+]) continue;
else break;
}
}
//计算找到如果没有回文重排点的右半边最小位置
int last = n;
int index=;
while(last>=index){
if(n& && last==(n+)/ && cnt[a[last]]&) {last--;continue;}
else if(n& && last==(n+)/) break;
if(last<=n/){
if(maxMid) last-=maxMid;
break;
}
else {
if(last>=n-index+ && a[last]!=a[n-last+]) break;
if(use[a[last]]+>cnt[a[last]]/) break;
else use[a[last]]++ , last--;
}
}
if(last<index) last=index;
// cout<<"last: "<<last<<endl;
/*----------------*/
if(mxRg>n) mxRg=n;
for(int index= ; index<=mxRg ; index++){
int flag = index*n;
int val = max(n-index+ , n-maxMatch);
// cout<<"first: "<<index<<" "<<last<<endl;
if(val == n-index+) ans+=n-(last<index?index:last)+;
else ans+=maxMatch+;//前面如果整个序列是回文串就会直接输出答案,所以这里maxMatch不可能会超过一半
// cout<<index<<" "<<ans<<endl;
}
printf("%I64d\n" , ans);
return ;
}

cf 501D

E题题意:

就是给定一个数字序列,任取一段区间重新排列,要是能找到一种排列方式使之后形成的整个序列是个回文序列,就说明取的这段区间是个合法区间

问有多少个合法区间

这题目开始考虑区间[l,r]合法,那么说明取[l , r'] r'>r均合法

那么只要枚举每一位l,快速找到最小的r即可用ans+=n-r+1就能算出来

将序列本身是回文的和序列永远无法变成回文特判,相信这个大家都认为是很简单的

我们找到一段从左端开始,和最右端开始的回文匹配得到能匹配到的最大值

 //从左右两端出发能匹配到的最大次数
int maxMatch = ;
for(int i=,j=n ; i<=j ; i++,j--){
if(a[i]==a[j])maxMatch++;
else break;
}
if(maxMatch==(n+)/){
printf("%I64d\n" , (ll)n*(n+)/);
return ;
}

我们每次得到一个新的l,如果这个l之前的串都已经能被回文匹配,说明那一段无论如何都取的到,那只要知道我任意匹配所能走到r的最小位置

如果没有满足全部回文匹配,那么说明最多只能从回文断开的地方取区间,总大小正好是maxMatch+1;

比如r可以从当前位置n走,在走过一半前只要判断取到的数是否超过原个数的一半即可,没超过说明合法

如果走过了一半 说明前面取到的数正好是一半,只要当前能够跟对应的位置匹配就可以取不取都无所谓了

这里我觉得还要考虑一个正好到奇数个数的中点的特判,保证那个位置是唯一出现的奇数个数的数即可

根据上述方法,再计算一个可枚举的l范围从1到k停止,也是根据上方所述一步步走:

 //计算最右侧出发还存在值的最大位置
int mxRg = ;
for(mxRg= ; mxRg<=n ; mxRg++){
if(n& && mxRg==(n+)/ && cnt[a[mxRg]]&) continue;
else if(n& && mxRg==(n+)/) break;
if(mxRg<=(n+)/){
if(use1[a[mxRg]]+<=cnt[a[mxRg]]/) {use1[a[mxRg]]++;continue;}
else break;
}
else {
if(a[mxRg]==a[n-mxRg+]) continue;
else break;
}
}
if(mxRg>n) mxRg=n;

得到那个最小的位置last后结果就很容易算了

 for(int index= ; index<=mxRg ; index++){
int flag = index*n;
int val = max(n-index+ , n-maxMatch);
// cout<<"first: "<<index<<" "<<last<<endl;
if(val == n-index+) ans+=n-(last<index?index:last)+;
else ans+=maxMatch+;//前面如果整个序列是回文串就会直接输出答案,所以这里maxMatch不可能会超过一半
// cout<<index<<" "<<ans<<endl;
}
 #include <bits/stdc++.h>

 using namespace std;
const int N = ;
int n , a[N] , cnt[N] , use[N] , use1[N];
#define ll long long
ll ans;
int main()
{
// freopen("a.in" , "r" , stdin);
scanf("%d" , &n);
int time =;
for(int i= ; i<=n ; i++){
scanf("%d" , &a[i]);
if(cnt[a[i]]==) time++;
cnt[a[i]]++;
}
if(time==){
printf("%I64d\n" , (ll)n*(n+)/);
return ;
}
int odd = ;
for(int i= ; i<=n ; i++){
if(cnt[i]&) odd++;
}
if(((n&)== && odd) || ((n&)&&odd>)){
puts("");
return ;
}
//从左右两端出发能匹配到的最大次数
int maxMatch = ;
for(int i=,j=n ; i<=j ; i++,j--){
if(a[i]==a[j])maxMatch++;
else break;
}
//从中间出发能匹配到的最大次数
int maxMid = ;
for(int i=n/ , j=(n+)/+; i> ; i-- , j++){
if(a[i]==a[j])maxMid++;
else break;
}
ans = ;
int last = n; //计算最右侧出发还存在值的最大位置
int mxRg = ;
for(mxRg= ; mxRg<=n ; mxRg++){
if(n& && mxRg==(n+)/ && cnt[a[mxRg]]&) continue;
else if(n& && mxRg==(n+)/) break;
if(mxRg<=(n+)/){
if(use1[a[mxRg]]+<=cnt[a[mxRg]]/) {use1[a[mxRg]]++;continue;}
else break;
}
else {
if(a[mxRg]==a[n-mxRg+]) continue;
else break;
}
}
if(mxRg>n) mxRg=n;
for(int index= ; index<=mxRg ; index++){
int flag = index*n;
last = max(n-index+ , n-maxMatch);
// cout<<"first: "<<index<<" "<<last<<endl;
if(last<n && last == n-index+) cnt[a[last+]] -= ;
while(last>=index){
if(n& && last==(n+)/ && cnt[a[last]]&) {last--;continue;}
else if(n& && last==(n+)/) break;
if(last<=n/){
if(maxMid) last-=maxMid;
break;
}
else {
if(use[a[last]]<flag) use[a[last]]=flag;
if(last>=n-index+ && a[last]!=a[n-last+]) break;
if(use[a[last]]+-flag>cnt[a[last]]/) break;
else use[a[last]]++ , last--;
}
}
if(last<index) last=index;
// cout<<index<<": "<<last<<" "<<maxMid<<endl;
ans += n-last+;
}
printf("%I64d\n" , ans);
return ;
}

cf501E

codeforces 501 C,D,E的更多相关文章

  1. codeforces 501 B Misha and Changing Handles 【map】

    题意:给出n个名字变化,问一个名字最后变成了什么名字 先用map顺着做的,后来不对, 发现别人是将变化后的那个名字当成键值来做的,最后输出的时候先输出second,再输出first 写一下样例就好理解 ...

  2. Codeforces Round #501 (Div. 3) F. Bracket Substring

    题目链接 Codeforces Round #501 (Div. 3) F. Bracket Substring 题解 官方题解 http://codeforces.com/blog/entry/60 ...

  3. Codeforces Div3 #501 A-E(2) F以后补

    感觉自己有点强迫症  不都写出来就找理由不写题解 http://codeforces.com/contest/1015   题目链接 A. Points in Segments 题目意思  n个线段  ...

  4. Codeforces Round #501 (Div. 3) D. Walking Between Houses

    题目链接 题意:给你三个数n,k,sn,k,sn,k,s,让你构造一个长度为k的数列,使得相邻两项差值的绝对值之和为sss, ∑i=1n∣a[i]−a[i−1]∣,a[0]=1\sum_{i=1}^n ...

  5. Codeforces Round #501 (Div. 3) 1015D Walking Between Houses

    D. Walking Between Houses time limit per test 2 seconds memory limit per test 256 megabytes input st ...

  6. Codeforces Round #501 (Div. 3) 1015A Points in Segments (前缀和)

    A. Points in Segments time limit per test 1 second memory limit per test 256 megabytes input standar ...

  7. 【Codeforces Round #501 (Div. 3)】

    A:https://www.cnblogs.com/myx12345/p/9842904.html B:https://www.cnblogs.com/myx12345/p/9842964.html ...

  8. Codeforces Round #501 (Div. 3)

    A - Points in Segments 题意:implement #include<bits/stdc++.h> using namespace std; typedef long ...

  9. Codeforces Round #501 (Div. 3) D. Walking Between Houses (思维,构造)

    题意:一共有\(n\)个房子,你需要访问\(k\)次,每次访问的距离是\(|x-y|\),每次都不能停留,问是否能使访问的总距离为\(s\),若能,输出\(YES\)和每次访问的房屋,反正输出\(NO ...

随机推荐

  1. Linux Shell 文本处理工具集锦 zz

    内容目录: find 文件查找 grep 文本搜索 xargs 命令行参数转换 sort 排序 uniq 消除重复行 用tr进行转换 cut 按列切分文本 paste 按列拼接文本 wc 统计行和字符 ...

  2. "rel=nofollow"属性

    nofollow是HTML元标签(meta)的content属性和链接标签(a)的rel属性的一个值,告诉机器(爬虫)无需追踪目标页,为了对抗blogspam(博客垃圾留言信息),Google推荐使用 ...

  3. Linux内核创建一个新进程

    张雨梅   原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-10000 创建新进程 如果同一个程序被多 ...

  4. mysql 正则篇

    一.SQL模式 SQL的模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零个字符).在 MySQL中,SQL的模式缺省是忽略大小写的.下面显示一些例子.注意在你使用SQL模式时 ...

  5. Solr Cloud - SolrCloud

    关于 Solr Cloud Zookeeper 入门,介绍 原理 原封不动转自 http://wiki.apache.org/solr/SolrCloud/ ,文章的内存有些过时,但是了解原理. Th ...

  6. contiki-断点的保存和恢复

    保存断点 保存断点是通过保存行数来完成的,在被中断的地方插入编译器关键字_LINE_,编译器便自动记录所终端的行数.展开那些具有中断功能的宏,可以发现最后保存行数是宏LC_SET,取宏PROCESS_ ...

  7. 【转】 linux内存管理

    一 为什么需要使用虚拟内存 大家都知道,进程需要使用的代码和数据都放在内存中,比放在外存中要快很多.问题是内存空间太小了,不能满足进程的需求,而且现在都是多进程,情况更加糟糕.所以提出了虚拟内存,使得 ...

  8. Excel公式学习

    1.Left函数 (1)语法格式=left(text,num_chars) ,(text代表用来截取的单元格内容,num_chars代表从左开始截取的字符数): (2)示例:例如A1单元格内的文本为: ...

  9. GO语言学习

    1. 语言特色 可直接编译成机器码,不依赖其他库,glibc的版本有一定要求,部署就是扔一个文件上去就完成了. 静态类型语言,但是有动态语言的感觉,静态类型的语言就是可以在编译的时候检查出来隐藏的大多 ...

  10. 解决UIButton 连续点击重复响应事件问题

    经常会遇到重复点击某个按钮 事件被响应多次的情景, 有时候可能对程序本身并没有什么影响 , 可有时候偏偏需要限制button响应事件直接的间隔 . 方法一 : 标记 1 . 利用空闲enable属性来 ...