题目:
A Jzzhu and Children ------ CodeForces 450A
B Jzzhu and Sequences ------ CodeForces 450B
C Jzzhu and Chocolate ------ CodeForces 449A
D Jzzhu and Cities ------ CodeForces 449B
E Jzzhu and Apples ------ CodeForces 449C
A题:n个数字每次从前到后每个数字-m 问哪个数字最后减到0 (水题)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef __int64 LL;
#define N 100010
int n,m,ans;
int main()
{
int i,x,y;
scanf("%d%d",&n,&m);
for(i=1,y=-1;i<=n;i++)
{
scanf("%d",&x);
if(x/m+(x%m!=0)>=y)
{
y=x/m+(x%m!=0);
ans=i;
}
}
printf("%d\n",ans);
return 0;
}
将递推公式变形 fi = fi-1 - fi-2 则可以推出循环节为6 然后直接计算
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef __int64 LL;
#define N 100010
#define mod 1000000007
LL x,y,n,ans;
int main()
{
scanf("%I64d%I64d%I64d",&x,&y,&n);
n%=6;
switch(n)
{
case 0: ans=x-y; break;
case 1: ans=x; break;
case 2: ans=y; break;
case 3: ans=y-x; break;
case 4: ans=-x; break;
case 5: ans=-y; break;
}
printf("%I64d\n",(ans%mod+mod)%mod);
return 0;
}
C题:切巧克力 只能在凹进去的地方横切或者竖切 问 n*m的巧克力切k刀后最小块面积最大能有多大 (想法题)
首先如果k比n+m-2大 一定输出-1
接着考虑切的策略 为了使最小块最大 我们应该尽量少分几份
那么就是说尽量在一个方向切(要么都横切要么都竖切)
然后开始讨论 如果在一个方向能把k刀都切掉 那么判断一下是横切优还是竖切优
最后 如果一个方向切不下k刀 那么必然要两个方向都切
很明显应该先切长边 因为这样切分的块数最少
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
LL n,m,k;
int main()
{
scanf("%I64d%I64d%I64d",&n,&m,&k);
if(n+m-2<k) printf("-1\n");
else if(n%(k+1)==0||m%(k+1)==0) printf("%I64d\n",n*m/(k+1));
else
{
if(n<m) swap(n,m);
if(m-1>=k) printf("%I64d\n",max(m/(k+1)*n,n/(k+1)*m));
else if(n-1>=k) printf("%I64d\n",n/(k+1)*m);
else printf("%I64d\n",m/(k-n+2));
}
return 0;
}
D题:n个城市之间有公路和铁路 每条路都是双向的且长度已知 铁路一定是从1城市到某个城市 现在要删掉尽量多的铁路线 但要保持1城市到每个城市的最短路径不变 问最多删几条 (图论题)
因为要多删铁路线 所以能走公路就走公路 但要保证最短路径不变
由此得出策略 我们从1城市开始做最短路 按照能走公路就走公路的原则求完整幅图的最短路 这时在最短路径上的铁路线就是不可以被删去的 那么删去的条数计算一下即可
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef __int64 LL;
#define N 100010
int n,m,k,tot,ans;
int vis[N],head[N],pre[N];
LL dis[N];
struct edge
{
int v,w,kind,next;
}ed[N*8];
struct node
{
int idx;
LL dis;
bool operator<(const node fa) const
{
return dis>fa.dis;
}
}u,v;
priority_queue<node> qu;
void add(int u,int v,int w,int kind)
{
ed[tot].v=v;
ed[tot].w=w;
ed[tot].kind=kind;
ed[tot].next=head[u];
head[u]=tot++;
}
void bfs()
{
int i;
u.dis=0; u.idx=1;
qu.push(u);
while(!qu.empty())
{
do
{
u=qu.top();
qu.pop();
}while(vis[u.idx]&&!qu.empty());
if(vis[u.idx]) return ;
vis[u.idx]=1;
if(pre[u.idx]!=-1) ans+=ed[pre[u.idx]].kind;
for(i=head[u.idx];~i;i=ed[i].next)
{
v.idx=ed[i].v;
v.dis=u.dis+ed[i].w;
if(!vis[v.idx])
{
if(dis[v.idx]==v.dis&&!ed[i].kind) pre[v.idx]=i;
if(!dis[v.idx]||dis[v.idx]>v.dis)
{
pre[v.idx]=i;
dis[v.idx]=v.dis;
qu.push(v);
}
}
}
}
}
int main()
{
int i,u,v,w;
memset(head,-1,sizeof(head));
memset(pre,-1,sizeof(pre));
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,0);
add(v,u,w,0);
}
for(i=1;i<=k;i++)
{
scanf("%d%d",&v,&w);
add(1,v,w,1);
}
bfs();
printf("%d\n",k-ans);
return 0;
}
E题:有1到n的数字 为它们两两分一组 要求分在一组的数字不互素 问最多分几组 并给出方案(数论题)
偶数对我们来说是最友好的 因为所有的偶数都可以组队 奇数里的素数尤其不友好
利用上述想法可以枚举素数(不是从2开始 是从3开始) 将因子包含该素数的数字全部找出来
这时如果有偶数个数 那么直接可以两两分组
如果有奇数个数(但不是一个) 那么我们从里面扔掉一个偶数 之后两两分组
最后剩下的数要么是找不到分组的数 要么是偶数 我们将偶数两两分组 就得出了答案
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef __int64 LL;
#define N 100010
int n,cnt,ans;
int flag[N],p[N],vis[N];
vector< pair<int,int> > v;
void get_prime()
{
int i,j;
for(i=2;i<=n;i++)
{
if(!flag[i]) p[cnt++]=i;
for(j=0;j<cnt&&p[j]*i<=n;j++)
{
flag[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
int main()
{
int i,j,k;
scanf("%d",&n);
get_prime();
for(i=1;i<cnt;i++)
{
vector<int> tmp;
for(j=p[i];j<=n;j+=p[i])
{
if(!vis[j]) tmp.push_back(j);
}
k=tmp.size();
if(k==1) continue;
if(k%2==1)
{
for(vector<int>::iterator it=tmp.begin();it!=tmp.end();it++)
{
if(*it%2==0)
{
tmp.erase(it);
k--;
break;
}
}
}
for(j=0;j<k;j+=2)
{
vis[tmp[j]]=1;
vis[tmp[j+1]]=1;
v.push_back(make_pair(tmp[j],tmp[j+1]));
ans++;
}
}
for(i=2,j=0;i<=n;i+=2)
{
if(!vis[i])
{
if(j)
{
v.push_back(make_pair(j,i));
ans++;
j=0;
}
else j=i;
}
}
printf("%d\n",ans);
for(i=0;i<ans;i++) printf("%d %d\n",v[i].first,v[i].second);
return 0;
}
PS:昨天逃掉了比赛今天才来补题TAT 要鞭策自己更加勤奋才行!!!