【题目传送门】http://7xjob4.com1.z0.glb.clouddn.com/30a7f1a788b43f34819586f3593d670a
【Problem A. Adjustment Office 】
【题意】 给了一个N*N的矩阵,矩阵中每个坐标为x,y的格子的值为x+y。有Q个询问,询问一行或者一列的和,然后清空这一行或者一列。
【解题方法】脑洞题。由于每次都要清空,所以一个点的权值只会被加一次,并且权值的分布相当有规律。所以只需要统计一下那些行哪些列被访问过了。以后询问的时候,先加上所有的权值,再减去哪些被询问过的位置的权值,总的复杂度是O(q)的。
【AC 代码】
#include<bits/stdc++.h>
using namespace std;
const int N =2e6;
#define LL long long
LL c,r,numc,numr;
int flagc[N],flagr[N];
int main()
{
freopen("adjustment.in","r",stdin);
freopen("adjustment.out","w",stdout);
int n,q,t;
char s[5];
scanf("%d%d",&n,&q);
for(int i=0;i<q;i++){
scanf("%s%d",s,&t);
if(s[0]=='R'){
if(flagr[t]==0) {
printf("%I64d\n",1ll*(2*t+1+n)*n/2-numc*t-c);
numr++;
r+=t;
flagr[t]=1;
}
else printf("0\n");
}
else{
if(flagc[t]==0){
printf("%I64d\n",1ll*(2*t+1+n)*n/2-numr*t-r);
numc++;
c+=t;
flagc[t]=1;
}
else printf("0\n");
}
}
return 0;
}
【Problem E. Easy Problemset】
【题意】难得解释,看题了。
【解题方法】水题,简单模拟一下就可以了。
【AC 代码】
//
//HDU 4417
//Created by just_sort 2016/8/22
//All Rights Reserved
//
#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[12][12];
int b[200];
int main()
{
freopen("easy.in","r",stdin);
freopen("easy.out","w",stdout);
scanf("%d%d",&n,&k);
int x[12];
int cnt=1,maxx=-1;
for(int i=1; i<=n; i++){
scanf("%d",&x[i]);
maxx=max(maxx,x[i]);
for(int j=1; j<=x[i]; j++){
scanf("%d",&a[i][j]);
}
}
memset(b,0,sizeof(b));
int j=1;
for(int i=1; i<=maxx; i++){
while(j<=n){
if(i<=x[j])
b[cnt++]=a[j][i];
else b[cnt++]=50;
j++;
}
j=1;
}
//for(int i=1; i<cnt; i++) printf("%d ",b[i]);puts("");
int step=0,ans=0;
for(int i=1; i<cnt; i++)
{
if(b[i]>=ans){
ans+=b[i];
step++;
if(step==k) break;
}
}
//cout<<ans<<endl;
ans=ans+(k-step)*50;
printf("%d\n",ans);
return 0;
}
【Problem F. Froggy Ford】
【题意】青蛙过河,河中有若干个石头,现在你可以加一个石头,使得青蛙从左岸跳到右岸的最大跳跃距离最小。
【解题方法】把左岸和右岸作为两个虚节点,用kruskal的思路处理出每个点到左岸需要跳跃的最大距离st[i](最优情况下)和每个点到右岸的最大距离ed[i],然后枚举两个点,在这两个点的中点放一个石头,得到ma=max(st[i],ed[j],dis(i,j)/2),如果这个值比答案更优,就更新答案,同时记录新放的石头的坐标。
【AC 代码】
//
//F Froggy Ford
//Created by just_sort 2016/8/24
//All rights Reserved
//
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1005;
double g[maxn][maxn];
double w;
bool vis[maxn];
int px[maxn],py[maxn];
int getdis(int i,int j)
{
return sqrt(double((px[i]-px[j])*(px[i]-px[j])+(py[i]-py[j])*(py[i]-py[j])));
}
void zxPrim1(int n,double dis[])
{
for(int i=1; i<=n; i++) dis[i] = px[i];
memset(vis,0,sizeof(vis));
for(int i=1; i<n; i++)
{
double minn=1e18;
int mark = 0;
for(int j=1; j<=n; j++) if(!vis[j]&&dis[j]<minn){mark=j; minn=dis[j];}
if(!mark) break;
vis[mark]=1;
for(int j=1; j<=n; j++)
if(!vis[j]&&dis[j]>max(minn,1.0*g[mark][j])) dis[j] = max(minn,1.0*g[mark][j]);
}
}
void fxPrim2(int n,double dis[])
{
for(int i=1; i<=n; i++) dis[i] = (w-px[i])*1.0;
memset(vis,0,sizeof(vis));
for(int i=1; i<n; i++)
{
double minn=1e18;
int mark=0;
for(int j=1; j<=n; j++) if(!vis[j]&&dis[j]<minn) {mark=j;minn=dis[j];};
if(!mark) break;
vis[mark] = 1;
for(int j=1; j<=n; j++)
if(!vis[j]&&dis[j]>max(minn,1.0*g[mark][j])) dis[j] = max(minn,1.0*g[mark][j]);
}
}
double dis1[maxn],dis2[maxn];
int main()
{
int n;
scanf("%lf%d",&w,&n);
for(int i=1; i<=n; i++) scanf("%d%d",&px[i],&py[i]);
for(int i=1; i<=n; i++){
for(int j=1; j<i; j++){
g[i][j]=g[j][i]=getdis(i,j);
}
}
zxPrim1(n,dis1);
fxPrim2(n,dis2);
double ans = 1e18;
double ansx = w/2.0,ansy = 0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(i!=j)
{
double temp = max(dis1[i],max(dis2[j],g[i][j]/2));
if(ans>temp)
{
ans = temp;
ansx = 1.0*(px[i]+px[j])/2.0;
ansy = 1.0*(py[i]+py[j])/2.0;
}
}
}
}
for(int i=1; i<=n; i++)
{
double temp = max(px[i]/2.0,dis2[i]);
if(ans>temp)
{
ans = temp;
ansx = 1.0*px[i]/2.0;
ansy = 1.0*py[i];
}
temp = max((w-px[i])/2.0,dis1[i]);
if(ans>temp)
{
ans = temp;
ansx = 1.0*(px[i]+w)/2.0;
ansy = 1.0*py[i];
}
}
printf("%.3f %.3f\n",ansx,ansy);
return 0;
}
【Problem G. Generators】
【题意】给n个序列和一个数k,但是这里n个数的序列式通过x[i]=(x0*a+b)%c确定下来的,然后从这n个序列里面分别选择1个数,使得这n个数的和对k取余不等于0。求最大的和。
【解体方法】容易想到在不超过c次的操作后,每个序列将出现循环,因此我们完全可以保存每个序列的信息,但是我们这里在生成的序列的过程中,直接保存每个序列里面的最大值和次大值得信息。然后得到了最大值的和,如果膜上k不等于0的话,就直接输出答案,否则分别用每个序列的次大值替换相应的最大值,维护最大的答案。注意判断无解,还有记录位置信息。
【AC 代码】
#include<cstdio>
#include<cstring>
using namespace std;
const int N =11000;
#define LL long long
struct node
{
int id,x,mod;
} dp[N][2];
int flag[1100];
int main()
{
freopen("generators.in","r",stdin);
freopen("generators.out","w",stdout);
int n,x0,a,b,c;
LL k;
scanf("%d%I64d",&n,&k);
for(int i=0; i<n; i++)
{
dp[i][0].x=-1;
dp[i][1].x=-1;
dp[i][0].mod=-1;
dp[i][1].mod=-1;
}
for(int i=0; i<n; i++)
{
memset(flag,0,sizeof(flag));
scanf("%d%d%d%d",&x0,&a,&b,&c);
int t=x0,cnt=0;
while(flag[t]==0)
{
flag[t]=1;
if(t>dp[i][0].x)
{
if(dp[i][0].x==-1)
{
dp[i][0]= {cnt,t,(int)((1ll*t)%k)};
}
else if(dp[i][0].mod==(int)((1ll*t)%k))
{
dp[i][0]= {cnt,t,(int)((1ll*t)%k)};
}
else
{
dp[i][1]=dp[i][0];
dp[i][0]= {cnt,t,(int)((1ll*t)%k)};
}
}
else if(dp[i][1].x<t)
{
if((int)((1ll*t)%k)!=dp[i][0].mod) dp[i][1]= {cnt,t,(int)((1ll*t)%k)};
}
cnt++;
t=(t*a+b)%c;
}
}
/*for(int i=0;i<n;i++){
printf("%d %d %d",dp[i][0].id,dp[i][0].x,dp[i][0].mod);
printf(" %d %d %d\n",dp[i][1].id,dp[i][1].x,dp[i][1].mod);
}*/
LL sum=0;
for(int i=0; i<n; i++)
{
sum+=dp[i][0].x;
}
if(sum%k!=0)
{
printf("%I64d\n",sum);
for(int i=0; i<n; i++)
{
printf("%d ",dp[i][0].id);
}
return 0;
}
LL ans=-1;
int ff=-1;
for(int i=0; i<n; i++)
{
if(dp[i][1].x==-1) continue;
else
{
if(ans<sum-dp[i][0].x+dp[i][1].x)
{
ans=sum-dp[i][0].x+dp[i][1].x;
ff=i;
}
}
}
if(ans==-1) printf("-1\n");
else
{
printf("%I64d\n",ans);
for(int i=0; i<n; i++)
{
if(ff==i) printf("%d ",dp[i][1].id);
else printf("%d ",dp[i][0].id);
}
}
return 0;
}