http://codeforces.com/contest/514/problem/A
给你一个数字,你可以对其每一位进行翻转操作:假如原来这个数字大小为 i ,翻转后就变为 9−i ,问翻转后数字最小是多少
水题
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 110
using namespace std;
int n;
char A[MAXN],B[MAXN];
char ans[MAXN];
int main()
{
scanf("%s",A+1);
n=strlen(A+1);
if(9-(A[1]-'0')<=(A[1]-'0')&&(9-(A[1]-'0')))
B[1]='0'+(9-(A[1]-'0'));
else B[1]=A[1];
for(int i=2;i<=n;i++)
{
if(9-(A[i]-'0')<=(A[i]-'0'))
B[i]='0'+(9-(A[i]-'0'));
else B[i]=A[i];
}
printf("%s\n",B+1);
return 0;
}
http://codeforces.com/contest/514/problem/B
给你 n 个点,问有多少个子集,使得子集里每个点和 (x0,y0) 都在同一直线上
枚举每个点,得到它们各自和 (x0,y0) 的连线的斜率,然后用并查集合并斜率相同的点即可。
注意此题卡double精度,还有要注意分母为0的情况,判断斜率是否相同时最好做移项,使用整数运算,避免除法
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>
#define MAXN 1100
#define EPS 1e-10
using namespace std;
int n;
typedef pair<int,int> pr;
pr points[MAXN],center;
int f[MAXN];
int findSet(int x)
{
if(f[x]==x) return f[x];
return f[x]=findSet(f[x]);
}
int main()
{
for(int i=1;i<MAXN;i++) f[i]=i;
scanf("%d%d%d",&n,¢er.first,¢er.second);
for(int i=1;i<=n;i++)
scanf("%d%d",&points[i].first,&points[i].second);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
if(!(points[i].second-center.second)||!(points[j].second-center.second)) continue;
if((points[i].first-center.first)*(points[j].second-center.second)==(points[j].first-center.first)*(points[i].second-center.second))
{
f[findSet(i)]=f[findSet(j)];
}
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
if(!(points[i].second-center.second)&&!(points[j].second-center.second))
{
f[findSet(i)]=f[findSet(j)];
}
}
int tot=0;
for(int i=1;i<=n;i++)
{
if(findSet(i)==i) tot++;
}
printf("%d\n",tot);
return 0;
}
http://codeforces.com/contest/514/problem/C
给你 n 个字符串, m 次询问一个串 S ,是否能在原来 n 个串中找到一个字符串,并在这个串里修改一个字符,使得这个串和 S 相同
把所有的串插入进trie树里,然后每次询问把 S 串拿来在trie树里DFS,并记录走到当前的trie结点时,是否已经修改过 S 串里的某个字符,如果匹配成功,且在遍历过程中仅修改了一次 S 串的字符,就表明能在原来 n 个串中找到一个字符串,并在这个串里修改一个字符,使得这个串和 S 相同。
说起来比较绕口,还是看代码比较清楚吧
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>
#define MAXN 610000
#define EPS 1e-10
using namespace std;
int n,m;
char s[MAXN];
int ch[MAXN][26],nCount=0,root=0;
void Insert()
{
int len=strlen(s+1),p=root;
for(int i=1;i<=len;i++)
{
if(!ch[p][s[i]-'a']) ch[p][s[i]-'a']=++nCount;
p=ch[p][s[i]-'a'];
}
}
int len;
bool DFS(int pos,int p,bool flag)
{
bool sol=false;
if(pos>len)
{
if(flag) return true;
return false;
}
if(ch[p][s[pos]-'a'])
if(DFS(pos+1,ch[p][s[pos]-'a'],flag))
return true;
if(!flag)
{
for(int i=0;i<26;i++)
if(s[pos]-'a'!=i&&ch[p][i])
if(DFS(pos+1,ch[p][i],true))
return true;
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
Insert();
}
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
len=strlen(s+1);
if(DFS(1,root,false)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
http://codeforces.com/contest/514/problem/D
给你一个 n 行 m 列的表格,每次操作时你可以选择其中一列,将这一列的元素全部减1(若某个元素为0,减1后不变,仍然是0),你最多可以操作 k 次,问操作完了以后,最多能有连续多少行的元素全部为0,输出一种可行方案。
显然操作 k 次不会比操作少于 k 次差。我们可以二分操作完了以后,最多能有连续多少行的元素全部为0,这样就转变为一个判定性问题:操作完了以后,是否最多能有连续 mid 行的元素全部为0。
我们可以 O(n−mid+1) 枚举 [L,R] 这段连续的行里全部变为0,显然要想实现这个目标,必须得要做 ∑1≤j≤mmaxL≤i≤R{a[i][j]} 次操作,为了快速求出这个值,我们可以建立 m 个线段树,分别维护每一列的区间最大值,然后就是查询线段树后做个求和就好了。 ∑1≤j≤mmaxL≤i≤R{a[i][j]}≤k ,就表明最多能有连续 mid 行的元素全部为0。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>
#define MAXN 110000
#define EPS 1e-10
using namespace std;
int n,m,K;
int mat[MAXN][6];
int maxans,ans[6],sol[6];
struct Segtree
{
int maxv[MAXN<<2];
void Build(int o,int L,int R,int id)
{
if(L==R)
{
maxv[o]=mat[L][id];
return;
}
int M=(L+R)>>1;
Build(o<<1,L,M,id);
Build(o<<1|1,M+1,R,id);
maxv[o]=max(maxv[o<<1],maxv[o<<1|1]);
}
int query(int o,int L,int R,int ql,int qr)
{
if(ql<=L&&R<=qr)
return maxv[o];
int M=(L+R)>>1,ans=0;
if(ql<=M) ans=max(ans,query(o<<1,L,M,ql,qr));
if(qr>M) ans=max(ans,query(o<<1|1,M+1,R,ql,qr));
return ans;
}
}segt[6];
bool check(int len)
{
for(int L=1,R=len;R<=n;L++,R++)
{
int sum=0;
for(int i=1;i<=m;i++)
sol[i]=segt[i].query(1,1,n,L,R);
for(int i=1;i<=m;i++)
sum+=sol[i];
if(sum<=K) return true;
}
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mat[i][j]);
for(int i=1;i<=m;i++)
segt[i].Build(1,1,n,i);
int lowerBound=1,upperBound=n;
maxans=-1;
while(lowerBound<=upperBound)
{
int mid=(lowerBound+upperBound)>>1;
if(check(mid))
{
lowerBound=mid+1;
maxans=mid;
for(int i=1;i<=m;i++) ans[i]=sol[i];
}
else upperBound=mid-1;
}
if(maxans!=-1)
{
for(int i=1;i<=m;i++)
printf("%d ",ans[i]);
printf("\n");
}
else
{
for(int i=1;i<=m;i++)
printf("0 ");
printf("\n");
}
return 0;
}