地址: http://codeforces.com/contest/1156
做了前3题,好不容易可以上分,结果不评分,有点难受。。
A. Inscribed Figures
思路:题目有点长。。,然后看了一半就直接看样例了(还是样例容易看懂),wa了一次,注意 3-1-2的情况有一个点是重合了
Code:
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_N=2e5+5;
int n,m,T;
int a[MAX_N];
int d[5][5];
int main()
{
ios::sync_with_stdio(false);
d[1][2]=3; d[1][3]=4;
d[2][1]=3; d[2][3]=-1;
d[3][1]=4; d[3][2]=-1;
cin>>n;
for(int i=0;i<n;++i)
cin>>a[i];
int ans=0;
for(int i=1;i<n;++i)
{
if(d[a[i-1]][a[i]]==-1){
ans=-1; break;
}
if(i>=2&&a[i-2]==3&&a[i-1]==1&&a[i]==2) --ans;
ans+=d[a[i-1]][a[i]];
}
if(ans!=-1){
cout<<"Finite"<<endl;
cout<<ans<<endl;
}else cout<<"Infinite"<<endl;
return 0;
}
B. Ugly Pairs
思路:构造题。开始题目看错了,以为相同的字符相邻是不可以的,写了半天没写出来,然后一看题目列表已经过了600多了,就觉得奇怪,应该没这么难,然后看样例就发现相同字符相邻是可以的QAQ. 这样的话就只要对不同的字符进行构造即可,然后改了下先前写的代码就ok了。。大体思路是从两端交替摆放。最后判断有多少个非法摆放,若小于1个则从非法处拆开再首位合并起来即可。
Code:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
int n,T;
int d[30];
char res[105];
string str;
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--){
memset(d,0,sizeof(d));
cin>>str;
n=str.length();
for(int i=0;i<n;++i)
++d[str[i]-'a'];
int l=0,r=25,s=0;
while(l<r){
while(l<r&&!d[l]){
++l;
}
while(r>l&&!d[r]){
--r;
}
if(l==r) break;
if(d[l]){
res[s++]=char(l+'a');
++l;
}
if(d[r]){
res[s++]=char(r+'a');
--r;
}
}
if(l==r&&d[l]){
res[s++]=char(l+'a');
}
int boo=0;
l=0;
if(abs(res[0]-res[s-1])==1) ++boo;
for(int i=1;i<s;++i)
if(abs(res[i]-res[i-1])==1){
++boo; l=i;
}
if(boo<=1){
for(int i=l;i<s;++i)
for(int j=0;j<d[res[i]-'a'];++j)
cout<<res[i];
for(int i=0;i<l;++i)
for(int j=0;j<d[res[i]-'a'];++j)
cout<<res[i];
cout<<endl;
}else cout<<"No answer"<<endl;
}
return 0;
}
C. Match Points
思路:贪心。比赛时是做了A(后来重测wa了。。)之后看题目发现C过的也挺多的,然后看下C就发现这题我做过啊,然后刷刷刷的就一遍过了^v^. 这题用贪心思路,先由小到大排序,在看要找的[l,r]都是一对对的,因此最多找到n/2个,因此将数组对半分,l从左半边开始,r从右半边开始找,每次用r去匹配l即可
Code:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX_N=2e5+5;
int n,m,T;
int a[MAX_N];
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0;i<n;++i)
cin>>a[i];
sort(a,a+n);
int ans=0;
int l=0,h=n/2,r=h;
while(l<h&&r<n){
if(a[r]-a[l]>=m){
++ans; ++l;
}
++r;
}
cout<<ans<<endl;
return 0;
}
D. 0-1-Tree
思路:树状DP。对每个节点作为路线的起点分析。假定1节点为整个树的根节点。首先DFS一遍找到以每个节点为根节点的树的d0[i],d1[i],d2[i]的数量。其中
d0[i]:以i节点为根节点的树中,从根节点出发路径权值都是0的路径数。
d1[i]:以i节点为根节点的树中,从根节点出发路径权值都是1的路径数。
d2[i]:以i节点为根节点的树中,从根节点出发路径权值开始是1后来是0的路径数。
在DFS一遍求出以每个节点为起点的合法路径数Si。而显然Si=d0[i]+d1[i]+d2[i]。但是这里的d0[i],d1[i],d2[i]应该是以i节点为整个树的根节点,而第一次DFS求的是以1节点为整个树的根节点下的 i节点的树。因此求Si时,需要将i节点的父亲节点的d0,d1,d2转移到 i节点上来,而这个转移则可通过 i节点和其父亲节点的连接线的权值w来分类讨论即可
Code:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int,int> pr;
const int MAX_N=2e5+5;
int n;
LL ans;
LL d0[MAX_N],d1[MAX_N],d2[MAX_N];
vector<pr> e[MAX_N];
/*
对每个点作为起点分析QAQ
*/
void DFS(int u,int pre);
void DFS1(int u,int pre);
int main()
{
ios::sync_with_stdio(false);
cin>>n;
int u,v,w;
for(int i=1;i<n;++i)
{
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
DFS(1,0);
DFS1(1,0);
cout<<ans<<endl;
return 0;
}
void DFS(int u,int pre)
{
int v,w;
for(auto c:e[u])
if(c.first!=pre){
v=c.first; w=c.second;
DFS(v,u);
if(!w){
d0[u]+=d0[v]+1;
}else{
d1[u]+=d1[v]+1;
d2[u]+=d2[v]+d0[v];
}
}
}
void DFS1(int u,int pre)
{
int v,w;
for(auto c:e[u])
if(c.first!=pre){
v=c.first; w=c.second;
if(!w){
d0[v]=d0[u];
}else{
d1[v]=d1[u];
d2[v]=d2[u]+d0[u]-d0[v];
}
DFS1(v,u);
}
ans+=d0[u]+d1[u]+d2[u];
}
E. Special Segments of Permutation
思路:二分+set
题目要求区间[l,r]中 a[l]+a[r]=max(a[l-->r]),对max{a[i]}继续分析,可以看出关键点max{a[i]},即最大值是影响到比它小的值的求解的。那么对a[l]+a[r]=a[i]的a[i]由大到小进行遍历,对于a[i]的区间边界l,r求解,肯定是包含a[i]且比a[i]大的点组成的边界,用d[i]记录值为i的点的下标值。这个可以用set自带的排序+二分查找来找到l,r.再求a[i]的解时,可以遍历[l,r]中离a[i]点近的一边x,再判断a[i]-x是否在另一边即可。在处理完a[i],在将a[i]点所处的位置下标加入set即可
Code:
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
typedef long long LL;
const int MAX_N=2e5+5;
int n;
LL ans;
int a[MAX_N],d[MAX_N];
set<int> iset;
void Find(int p,int l,int r);
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1,x;i<=n;++i)
{
cin>>a[i];
d[a[i]]=i;
}
iset.insert(0);
iset.insert(n+1);
int l,r;
set<int>::iterator f;
for(int i=n;i>=3;--i)
if(d[i]>1&&d[i]<n){
f=iset.lower_bound(d[i]);
r=*f; l=*(--f);
Find(i,l+1,r-1);
iset.insert(d[i]);
}
cout<<ans<<endl;
return 0;
}
void Find(int p,int l,int r)
{
int h=d[p];
if(h-l<r-h){
for(int i=l;i<h;++i)
if(p-a[i]>0&&d[p-a[i]]>h&&d[p-a[i]]<=r) ++ans;
}else{
for(int i=h+1;i<=r;++i)
if(p-a[i]>0&&d[p-a[i]]>=l&&d[p-a[i]]<h) ++ans;
}
}