FJUTOJ-周赛2016-11-25

时间:2023-03-09 15:45:45
FJUTOJ-周赛2016-11-25

注:fjutoj基本每周都有一次周赛,欢迎大家都来参加!

网址:http://59.77.139.92/ 或 acm.fjut.edu.cn

A题

题意:一年中,每个月有可能亏x 元,有可能赚y 元,每连续的五个月加起来都亏钱,问一年最多赚多少钱,如果不能赚钱,输出"Deficit"。

思路:

  贪心的思路,五个月中亏钱的月份放后面去,并且使得五个月加起来亏钱最少,因此共有4种情况:

  x y y y y x y y y y x y

  x x y y y x x y y y x x

  x x x y y x x x y y x x

  x x x x y x x x x y x x

  用if判断一下即可

 #include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
#define N 100010
#define M 100010
#define Mod 1000000007
#define LL long long
#define INF 0x7fffffff
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++)
#define For(i,f_start,f_end) for(int i=f_start;i<f_end;i++)
#define REP(i,f_end,f_start) for(int i=f_end;i>=f_start;i--)
#define Rep(i,f_end,f_start) for(int i=f_end;i>f_start;i--)
#define MT(x,i) memset(x,i,sizeof(x))
#define gcd(x,y) __gcd(x,y)
const double PI = acos(-); int main()
{
int x,y;
while(scanf("%d%d",&x,&y)!=EOF)
{
if(x>=*y) printf("Deficit\n");
else if(*x>*y)
{
if(*x<=*y) printf("Deficit\n");
else printf("%d\n",*x-*y);
}
else if(*x>=*y)
{
if(*x<=*y) printf("Deficit\n");
else printf("%d\n",*x-*y);
}
else if(*x>=y)
{
if(*x<=*y) printf("Deficit\n");
else printf("%d\n",*x-*y);
}
else
{
if(*x<=*y) printf("Deficit\n");
else printf("%d\n",*x-*y);
}
}
return ;
}

A题AC代码

B题

题意:规定了两种日历的格式,给出第一个日历日期,要求转化成第二种。

思路:简单题,考验新生的代码实现能力,并不需要什么思路,略过。

 #include<stdio.h>
#include<map>
#include<string>
#include<iostream>
using namespace std; map<string, int> mp;
map<int, string> pm;
int main()
{
mp["pop"]=; mp["no"]=; mp["zip"]=;
mp["zotz"]=; mp["tzec"]=; mp["xul"]=;
mp["yoxkin"]=; mp["mol"]=; mp["chen"]=;
mp["yax"]=; mp["zac"]=; mp["ceh"]=;
mp["mac"]=; mp["kankin"]=; mp["muan"]=;
mp["pax"]=; mp["koyab"]=; mp["cumhu"]=;
mp["uayet"]=; pm[]="imix"; pm[]="ik"; pm[]="akbal"; pm[]="kan"; pm[]="chicchan"; pm[]="cimi";
pm[]="manik"; pm[]="lamat"; pm[]="muluk"; pm[]="ok"; pm[]="chuen"; pm[]="eb";
pm[]="ben"; pm[]="ix"; pm[]="mem"; pm[]="cib"; pm[]="caban"; pm[]="eznab";
pm[]="canac"; pm[]="ahau"; int t;
scanf("%d",&t);
printf("%d\n",t);
while(t--)
{
int day=, mon, year;
string tmp;
scanf("%d.",&day); cin>>tmp; scanf("%d",&year);
mon=mp[tmp];
day = year* + mon* + day;
year = day/;
mon = day%;
day = day%;
printf("%d ",day+); cout<<pm[mon]; printf(" %d\n",year);
}
return ;
}

B题AC代码

C题

题意:字符串比较,第一个字符串多包含了*、?,*可以替换为任意多个任意字符,?可以替换为1个任意字符。

思路:数据量大时,用AC自动机做,因为该题数据量小,所以是简单题,递归一下更方便

 #include<stdio.h>
using namespace std; char head[], s[];
bool dfs(int i, int j)
{
if(head[i]== && s[j]==) return true;
else if(head[i]==) return false;
else if(s[j]==)
{
for(;head[i]!= && head[i]=='*';i++);
if(head[i]!=) return false;
else return true;
}
if('a'<=head[i] && head[i]<='z')
{
if(s[i]!=head[j]) return false;
else return dfs(i+, j+);
}
else if(head[i]=='?') return dfs(i+, j+);
else
{
int k;
for(k=i;head[k];k++)
{
if(head[k]!='*') break;
}
if(head[k]==) return true;
bool ret=false;
for(;s[j] && !ret;j++)
{
ret=dfs(k, j);
}
return ret;
}
} int main()
{
while(~scanf("%s",head))
{
int n;
scanf("%d",&n);
int co=;
while(n--)
{
scanf("%s",s);
if(dfs(,)) co++;
}
printf("%d\n",co);
}
return ;
}

C题AC代码

D题

题意:有一个坐标系,坐标系上有n个点,在同一行或同一列上的任意两点称为关联的,并且关联属性是可传递的,即A和B关联,B和C关联,则可认为A和C关联,现在问图中是否任意两点都是关联的。

n>=2 && n<=50万

每个点的坐标x、y满足 1<=x、y<=50000

思路:并查集,横、纵坐标最多50000,可以先对所有点按横坐标排序,然后遍历一遍,如果两点横坐标相同,他们的纵坐标就是一组的。

 #include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 500010 int fa[N];
int find(int x)
{
int p=x;
while(p!=fa[p]) p=fa[p];
int q;
while(fa[x]!=p)
{
q=fa[x];
fa[x]=p;
x=q;
}
return p;
}
void join(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy) fa[fx]=fy;
} struct Node
{
int x,y;
}v[N]; bool cmp(Node a,Node b)
{
if(a.x!=b.x) return a.x>b.x;
else return a.y<b.y;
} bool vis[N];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(vis,,sizeof(vis));
for(int i=;i<n;i++)
{
scanf("%d%d",&v[i].x,&v[i].y);
if(v[i].y>) while();
vis[v[i].y]=;
}
for(int i=;i<=;i++) fa[i]=i;
sort(v,v+n,cmp);
int prex=-, prey=-;
for(int i=;i<n;i++)
{
if(v[i].x!=prex)
{
prex=v[i].x;
prey=v[i].y;
}
else
{
join(prey, v[i].y);
}
}
int co=;
for(int i=;i<=;i++)
{
if(vis[i])
{
if(fa[i]==i) co++;
}
}
if(co==) printf("YES\n");
else printf("NO\n");
}
return ;
}

D题AC代码

E题

题意:给n个数,有m次询问,每次询问提供一个区间[l,r],每次求一个x使得FJUTOJ-周赛2016-11-25最小。

思路:划分树,基本是模板题了,略过。

 #include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 100010
#define LL long long
int sorted[N]; //排序好的数组
int num[][N]; //num[i] 表示i前面有多少个点进入左孩子
LL sum[][N];
int val[][N]; //20层,每一层元素排放,0层就是原数组
void build(int l,int r,int ceng)
{
if(l==r) return ;
int mid=(l+r)/,isame=mid-l+; //isame保存有多少和sorted[mid]一样大的数进入左孩子
for(int i=l;i<=r;i++) if(val[ceng][i]<sorted[mid]) isame--;
int ln=l,rn=mid+; //本结点两个孩子结点的开头,ln左
for(int i=l;i<=r;i++)
{
if(i==l) num[ceng][i]=, sum[ceng][i]=;
else num[ceng][i]=num[ceng][i-], sum[ceng][i]=sum[ceng][i-];
if(val[ceng][i]<sorted[mid] || val[ceng][i]==sorted[mid]&&isame>)
{
val[ceng+][ln++]=val[ceng][i];
num[ceng][i]++;
sum[ceng][i]+=val[ceng][i];
if(val[ceng][i]==sorted[mid]) isame--;
}
else
{
val[ceng+][rn++]=val[ceng][i];
}
}
build(l,mid,ceng+);
build(mid+,r,ceng+);
}
LL ans;
LL look(int ceng,int sl,int sr,int l,int r,int k,LL he)
{
if(sl==sr) return val[ceng][sl];
int ly; LL sy;
if(l==sl) ly=,sy=;
else ly=num[ceng][l-],sy=sum[ceng][l-];
int tolef=num[ceng][r]-ly;
LL ret;
if(tolef>=k)
{
ret = look(ceng+,sl,(sl+sr)/,sl+ly,sl+num[ceng][r]-,k,sum[ceng][r]-sy);
ans += (he-sum[ceng][r]+sy)-ret*(r-l+-tolef);
}
else
{
int lr = (sl+sr)/ + + (l-sl-ly);
ret = look(ceng+,(sl+sr)/+,sr,lr,lr+r-l+-tolef-,k-tolef,he-sum[ceng][r]+sy);
ans += ret*tolef-sum[ceng][r]+sy;
}
return ret;
} LL pre[N];
int main()
{
int cas=,t,n,m,l,r;
scanf("%d",&t);
while(t--)
{
printf("Case #%d:\n",cas++);
scanf("%d",&n);
pre[]=;
for(int i=;i<=n;i++)
{
scanf("%d",&val[][i]);
sorted[i]=val[][i];
pre[i]=pre[i-]+val[][i];
}
sort(sorted+,sorted+n+);
build(,n,);
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&l,&r);
l++, r++;
ans=;
look(,,n,l,r,(r-l+)/,pre[r]-pre[l-]);
printf("%I64d\n",ans);
}
printf("\n");
}
return ;
}

E题AC代码

总结:A题考逻辑能力,B题考代码能力,C题需要更高的代码能力,D题考简单的数据结构,E题考知识面。