前言:本篇文章的主要代码来自于CSDN博客或者网络,感谢网络ACMdalao的AC代码,佩服他们,本文最后会写出各个AC代码的原作者和网址。(注意一点,每个程序的头文件我都改成了万能头文件,测试时间可能会加长,如果需要源代码的头文件请直接在代码后面的链接里面去找一下,我喜欢C++里面不用类似于stdio.h的头文件写法的头文件,我可能会写成cstdio,注意,万能头文件在POJ里面是不能识别的,会出现CE,这个时候你就需要修改万能头文件成你所需要的头文件)
ACM-ICPC 2017南宁赛区网络赛题目及其题解
题目列表
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9 + 5;
const int MAXN = 100000007;
const int MOD = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1.0);
LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a%b); }
double MA[5][5];
int main()
{
double ans, res;
int x, y;
char ch;
for (int i = 1; i <= 4; i++)
for (int j = 1; j <= 4; j++)
scanf("%lf", &MA[i][j]);
ans = 1;
getchar();
y = -1;
while (scanf("%d", &x))
{
if (y == -1)
{
y = x;
continue;
}
else
{
ans *= MA[y][x];
y = x;
}
ch = getchar();
if (ch != ' ')
break;
}
printf("%.8f\n", ans);
y = -1;
ans = 1;
while (scanf("%d", &x))
{
if (y == -1)
{
y = x;
continue;
}
else
{
ans *= MA[y][x];
y = x;
}
ch = getchar();
if (ch != ' ')
break;
}
printf("%.8f\n", ans);
scanf("%d", &x);
ans = 0;
res = 1;
for (int i = 1; i <= 1000; i++)
{
ans += res;
res *= MA[x][x];
}
printf("%.8f\n", ans);
scanf("%d", &x);
ans = 0;
res = 1;
for (int i = 1; i <= 1000; i++)
{
ans += res;
res *= MA[x][x];
}
printf("%.8f\n", ans);
}
本题感谢Effiel大佬的AC代码,附上原作者题解地址:
http://blog.csdn.net/kele52he/article/details/78078507
B.Train Seats Reservation(暴力遍历)
题目链接:https://nanti.jisuanke.com/t/17309
题意:一辆火车从1开到n,给你几个从l上车,r下车的人数。让你求这辆火车至少要装多少座位才可以都坐下。
POINT:
数据很小,暴力,求区间1到n里同时人数最多的就行。注意r这个点的人是要下车的,可以同时上车。
代码如下:
#include
using namespace std;
#define LL long long
const LL maxn = 111;
LL a[maxn];
int main()
{
LL n;
while(~scanf("%lld",&n))
{
if(n==0)
{
printf("*\n");
break;
}
memset(a,0,sizeof a);
LL ans=0;
LL l,r,k;
for(LL j=1;j<=n;j++){
scanf("%lld %lld %lld",&l,&r,&k);
if(l>r) swap(l, r);
for(LL i=l;iif(ansprintf("%lld\n",ans);
}
}
感谢Mr_Treeeee的AC代码,下面给出原代码链接:
http://blog.csdn.net/mr_treeeee/article/details/78078435
C.Auction Bidding
题目链接:https://nanti.jisuanke.com/t/17310
本题暂时没找到AC代码,待补
D.Path Search with Constraints
题目链接:https://nanti.jisuanke.com/t/17311
本题暂时没找到AC代码,待补
E.Visible Surface
题目链接:https://nanti.jisuanke.com/t/17312
本题暂时没找到AC代码,待补
F.Overlapping Rectangles(离散+线段树,需要离散数学和数据结构的知识)
题目链接:https://nanti.jisuanke.com/t/17313
题意:计算矩形面积并
思路:主要用到了离散数学+线段树的知识,有模板的可以直接套用模板,然后修改一下就能过
PS:这道题我们队原来就没想着过,结果我们队的一个dalao直接用模板就AC了O(∩_∩)O哈哈~,当时就吃惊了,因为那个时候我们在死磕B(说句实话,我们的B花的时间太多了T^T,主要是想复杂了)
附上原作者的AC代码:
#include
using namespace std;
#define LL long long
const LL maxn = 1111;
#define lt x<<1
#define rt x<<1|1
LL a[maxn];
struct len
{
int l,r;
int kind;
int h;
}l[maxn*2];
struct ju
{
int a,b,c,d;
}z[maxn];
int p[maxn*2],num;
int pp[maxn*2];
int sum[maxn*8];
int add[maxn*8];
bool cmd(len a,len b)
{
// if(a.h!=b.h)
return a.hvoid pushdown(int x,int l,int r)
{
sum[lt]+=add[x];
add[lt]+=add[x];
sum[rt]+=add[x];
add[rt]+=add[x];
add[x]=0;
}
void change(int x,int l,int r,int ll,int rr,int kind)
{
if(add[x]!=0)
{
pushdown(x,l,r);
}
if(ll<=l&&rr>=r)
{
add[x]=kind;
sum[x]+=kind;
}
else
{
int mid=(l+r)>>1;
if(ll<=mid)
{
change(lt,l,mid,ll,rr,kind);
}
if(mid1,r,ll,rr,kind);
}
}
}
int query(int x,int l,int r)
{
if(add[x]) pushdown(x, l, r);
int ans=0;
if(l==r)
{
if(r==num) return 0;
if(sum[x]>0)
ans+=p[r+1]-p[l];
}
else
{
int mid=(l+r)>>1;
ans+=query(lt,l,mid);
ans+=query(rt,mid+1,r);
}
return ans;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n==0)
{
printf("*");
break;
}
num=0;
for(int i=1;i<=n;i++)
{
scanf("%d %d %d %d",&z[i].a,&z[i].b,&z[i].c,&z[i].d);
pp[++num]=z[i].a;
pp[++num]=z[i].c;
}
sort(pp+1,pp+1+num);
for(int i=1;i<=num;i++)
{
p[i]=pp[i];
}
int lennum=0;
for(int i=1;i<=n;i++)
{
l[++lennum].l=lower_bound(pp+1,pp+1+num,z[i].a)-pp;
l[lennum].r=lower_bound(pp+1,pp+1+num,z[i].c)-pp;
l[lennum].kind=1;
l[lennum].h=z[i].b;
l[++lennum].l=lower_bound(pp+1,pp+1+num,z[i].a)-pp;
l[lennum].r=lower_bound(pp+1,pp+1+num,z[i].c)-pp;
l[lennum].kind=-1;
l[lennum].h=z[i].d;
}
sort(l+1,l+1+lennum,cmd);
memset(sum,0,sizeof sum);
memset(add,0,sizeof add);
int ans=0;
for(int i=1;i<=lennum;i++)
{
int temp=query(1, 1, num);
if(i>=2)
{
ans+=temp*(l[i].h-l[i-1].h);
}
change(1,1,num,l[i].l,l[i].r-1,l[i].kind);
}
printf("%d\n",ans);
}
}
本题AC代码提供者还是Mr_Treeeee,感谢Mr_Treeeee的AC代码,下面给出原代码链接:
http://blog.csdn.net/mr_treeeee/article/details/78078435
G.Finding the Radius for an Inserted Circle(运算几何,二分)
题目链接:https://nanti.jisuanke.com/t/17314
这道题需要数学知识,具体看下面。
题意:这道题就是给你三个一模一样的圆,左边一个右边一个下面一个,三个圆两两相切,然后在这三个圆中间的地方找一个小圆,要求这个小圆与这三个大圆相切,这被称为一次操作,然后第二次操作的时候,就把下面的大圆替换成那个小圆,然后从这两个大圆和一个小圆中间再找一个更小的圆也与它们相切,最后问你经过k次操作后那个小圆的半径是多少。
思路:我们可以把三个圆的圆心两两相连,连成一个三角形,再把三个圆心与中间的小圆心相连,假设左右两个大圆的半径为R,下面的圆半径为r,中间的小圆半径为s,那么就可以转化成下图。
红色的边都是已知长度的,并且长度都在图中标记了出来,因为相切,所以两圆心的距离等于两圆半径之和。
那么我们可以对图中的蓝色边做文章,蓝色边的长度可以等于sqrt((R+s)^2-R^2),也可以等于sqrt((R+r)^2-R^2)-r-s。这样我们让这两个等式相等,就可以通过R和r求出s了,不过这个方程组里有根号,不是很好解,所以我们可以用二分的方法去寻找方程的解。s求出来后我们就完成了一次操作,然后把s的值赋给r,我们就可以进行第二次操作了。
PS:这道题本来我想先A的,结果看看有点复杂就没上手,赛后一看,炸了,几何题,瞬间爆炸,想打死自己了
下面是AC代码:(瞬间感觉自己数学要重学了)
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9 + 5;
const int MAXN = 100000007;
const int MOD = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1.0);
LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a%b); }
struct POINT
{
double x;
double y;
POINT(double a = 0, double b = 0) { x = a; y = b; } //constructor
};
struct LINESEG
{
POINT s;
POINT e;
LINESEG(POINT a, POINT b) { s = a; e = b; }
LINESEG() { }
};
double multiply(POINT sp, POINT ep, POINT op)
{
return((sp.x - op.x)*(ep.y - op.y) - (ep.x - op.x)*(sp.y - op.y));
}
bool InsideConvexPolygon(int vcount, POINT polygon[], POINT q) // 可用于三角形!
{
POINT p;
LINESEG l;
int i;
p.x = 0; p.y = 0;
for (i = 0; i// 寻找一个肯定在多边形polygon内的点p:多边形顶点平均值
{
p.x += polygon[i].x;
p.y += polygon[i].y;
}
p.x /= vcount;
p.y /= vcount;
for (i = 0; i1) % vcount];
if (multiply(p, l.e, l.s)*multiply(q, l.e, l.s)<0) /* 点p和点q在边l的两侧,说明点q肯定在多边形外 */
break;
}
return (i == vcount);
}
void find(int x, int y, int &X, int &Y)
{
double ox, oy;
POINT pp[6];
for (int i = -9; i <= 10; i++)
for (int j = -9; j <= 10; j++)
{
oy = 7.5*j;
ox = 5 * sqrt(3)*i + j*2.5*sqrt(3);
pp[0].x = ox;
pp[0].y = oy + 5;
pp[1].x = ox + 2.5*sqrt(3);
pp[1].y = oy + 2.5;
pp[2].x = ox + 2.5*sqrt(3);
pp[2].y = oy - 2.5;
pp[3].x = ox;
pp[3].y = oy - 5;
pp[4].x = ox - 2.5*sqrt(3);
pp[4].y = oy + 2.5;
pp[5].x = ox - 2.5*sqrt(3);
pp[5].y = oy - 2.5;
if (InsideConvexPolygon(6, pp, POINT(x, y)))
{
X = i;
Y = j;
return;
}
}
}
int main()
{
int x, y;
int X, Y;
scanf("%d%d", &x, &y);
find(x, y, X, Y);
printf("[%d,%d]", X, Y);
for (int i = 2; i <= 10; i++)
{
scanf("%d%d", &x, &y);
find(x, y, X, Y);
printf(", [%d,%d]", X, Y);
}
printf("\n");
}
本题感谢Effiel大佬的AC代码,附上原作者题解地址:
http://blog.csdn.net/kele52he/article/details/78079145
H.A Cache Simulator(组成原理水题)
题目链接:https://nanti.jisuanke.com/t/17315
这道题如果会组成原理的话,基本上能直接1A,组成原理的链接:
https://wenku.baidu.com/view/6ad6e27f76c66137ee061990.html
下面给出代码:
#include
using namespace std;
typedef long long ll;
ll a[(1<<6)+1];
char s[100];
int main()
{
// freopen("data.txt","r",stdin);
// ios_base::sync_with_stdio(false);
ll ct=0,ct1=0;
for(int i=0;i<(1<<6);i++)
{
a[i]=-1;
}
while(~scanf("%s",s))
{
if(strcmp(s,"END")==0)
break;
ct++;
int len=strlen(s);
ll sum=0;
ll t = 1;
for(int i=len-1;i>=0;i--)
{
if(s[i]>='0'&&s[i]<='9')
{
sum += (s[i]-48)*t;
}
else if(s[i]>='A'&&s[i]<='F')
{
sum += (s[i]-55)*t;
}
t*=16;
}
// cout << sum<
ll t1 = sum/(1<<10);
sum%=(1<<10);
ll tt = sum>>4;
sum%=64;
if(a[tt]==-1)
{
printf("Miss\n");
a[tt] =t1;
}
else
{
if(a[tt]==t1)
{
ct1++;
printf("Hit\n");
}
else
{
printf("Miss\n");
a[tt] =t1;
}
}
}
printf("Hit ratio = %.2lf%%\n",(double)ct1/(double)ct*100);
return 0;
}
感谢chudongfang2015大佬的AC代码,给出原链接地址:
http://blog.csdn.net/chudongfang2015/article/details/78080214
I.GSM Base Station Identification(暴力+计算几何)
题目链接:https://nanti.jisuanke.com/t/17316
PS:这道题是我第一个想写的题目,一看就感觉像三角定位法,结果一看不对,是六边形,瞬间脑子一片空白,然后读到最后感觉有点晕,就没写下去,赛后问了大佬之后,我还是感觉自己太naive了,居然可以暴力,瞬间炸了。
题意:有一个坐标系,每格的长度是5,然后在这个坐标系中有许多边长为5的正六边形,这些正六边形互相连接,没有空隙,每个正六边形都有一个自己的坐标,原点处的正六边形坐标是[0,0],然后每往右一个横坐标+1,每往左一个横坐标-1。然后右上方的纵坐标+1,左下方的纵坐标-1。这样每个正六边形都有属于自己的不同的坐标。现在给你一个坐标系中的坐标,问这个坐标所在的正六边形的坐标是多少。
思路:因为正六边形的横坐标和纵坐标的范围都是[-9,10],一共只有400个正六边形,所以我们可以把每一个正六边形都循环一遍,判断当前的这个点是否在该六边形中。现在的问题就是我们怎么判断这个点是否在坐标为[i,j]的正六边形中,我们首先可以根据i和j求出该正六边形的中心坐标,仔细观察后可以发现,oy=7.5*j,ox=5*sqrt(3)*i+2.5*sqrt(3)*j。然后我们可以根据中心的坐标求出周围六个顶点的坐标,之后我们就可以套用判断一个点是否在一个凸多边形内的模板,如果它在里面,那么当前的i和j就是答案坐标。
代码如下:
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9 + 5;
const int MAXN = 100000007;
const int MOD = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1.0);
LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a%b); }
struct POINT
{
double x;
double y;
POINT(double a = 0, double b = 0) { x = a; y = b; } //constructor
};
struct LINESEG
{
POINT s;
POINT e;
LINESEG(POINT a, POINT b) { s = a; e = b; }
LINESEG() { }
};
double multiply(POINT sp, POINT ep, POINT op)
{
return((sp.x - op.x)*(ep.y - op.y) - (ep.x - op.x)*(sp.y - op.y));
}
bool InsideConvexPolygon(int vcount, POINT polygon[], POINT q) // 可用于三角形!
{
POINT p;
LINESEG l;
int i;
p.x = 0; p.y = 0;
for (i = 0; i// 寻找一个肯定在多边形polygon内的点p:多边形顶点平均值
{
p.x += polygon[i].x;
p.y += polygon[i].y;
}
p.x /= vcount;
p.y /= vcount;
for (i = 0; i1) % vcount];
if (multiply(p, l.e, l.s)*multiply(q, l.e, l.s)<0) /* 点p和点q在边l的两侧,说明点q肯定在多边形外 */
break;
}
return (i == vcount);
}
void find(int x, int y, int &X, int &Y)
{
double ox, oy;
POINT pp[6];
for (int i = -9; i <= 10; i++)
for (int j = -9; j <= 10; j++)
{
oy = 7.5*j;
ox = 5 * sqrt(3)*i + j*2.5*sqrt(3);
pp[0].x = ox;
pp[0].y = oy + 5;
pp[1].x = ox + 2.5*sqrt(3);
pp[1].y = oy + 2.5;
pp[2].x = ox + 2.5*sqrt(3);
pp[2].y = oy - 2.5;
pp[3].x = ox;
pp[3].y = oy - 5;
pp[4].x = ox - 2.5*sqrt(3);
pp[4].y = oy + 2.5;
pp[5].x = ox - 2.5*sqrt(3);
pp[5].y = oy - 2.5;
if (InsideConvexPolygon(6, pp, POINT(x, y)))
{
X = i;
Y = j;
return;
}
}
}
int main()
{
int x, y;
int X, Y;
scanf("%d%d", &x, &y);
find(x, y, X, Y);
printf("[%d,%d]", X, Y);
for (int i = 2; i <= 10; i++)
{
scanf("%d%d", &x, &y);
find(x, y, X, Y);
printf(", [%d,%d]", X, Y);
}
printf("\n");
}
本题感谢Effiel大佬的AC代码,附上原作者题解地址:
http://blog.csdn.net/kele52he/article/details/78079145
J.Minimun Distance in a Star Graph(贪心思想)
题目链接:https://nanti.jisuanke.com/t/17317
题意:他啰里八嗦讲了一大堆。其实就是从a状态变成b状态。
每次只能把第一个数和另一个数交换。求最小的交换次数,从a变到b。
POINT:贪心思想。把b序列变成12345n,把a序列对印b起来。
若第一个数不是1,则把它归位,交换他们 ans++。
若是1,则把1和后面错误的数交换,ans++。
这样交换下去便是最小的交换次数,输出ans。
主要还是读懂题目。
下面给出代码:
#include
using namespace std;
int n,ans[10],mean[15];
int num[15];
int work()
{
int ans=0;
while(1)
{
if(num[1]!=1)
{
ans++;
swap(num[1],num[num[1]]);
}
else
{
int flag=0;
for(int i=1;i<=n;i++)
{
if(num[i]!=i)
{
flag=1;
ans++;
swap(num[1],num[i]);
break;
}
}
if(!flag) break;
}
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(mean,0,sizeof mean);
for(int i=1;i<=5;i++)
{
char s1[15],s2[15];
scanf("%s%s",s1,s2);
for(int i=0;i'0'] = i+1;
}
for(int i=0;i1] = mean[s1[i]-'0'];
printf("%d\n",work());
}
}
return 0;
}
本题AC代码提供者还是Mr_Treeeee,感谢Mr_Treeeee的AC代码,下面给出原代码链接:
http://blog.csdn.net/mr_treeeee/article/details/78078435
K.Line Segments Clipped by Windows
题目链接:https://nanti.jisuanke.com/t/17318
本题暂时还没有找到AC代码,待补
L.The Heaviest Non-decreasing Subsequence Problem(LIS,最长不递减子序列)
题目链接:https://nanti.jisuanke.com/t/17319
PS:这是我们最后死磕的一道题,2小时还没A,感觉心态真的爆炸,一上手看到这题就说是LIS,然后套模板,感觉不对又重新看了一边题目,发现还是LIS没变,模板改了20+,交上去不是WA就是CE,赛后问了才知道是要拆开解决,晕了。
题意:最长上升子序列。但是每个数的权值不一样,有的是1,有的是0,有的是5。求最大权值的最长上升子序列。
POINT:把权值为0的去掉,把权值为5的复制5个放进数组。
再跑一遍nlogn的最长上升子序列,就是答案。
下面给出代码:
#include
using namespace std;
#define LL long long
const LL maxn = 1e6+888;
int n=0;
int num[maxn];
int a[maxn];
int main()
{
int q;
while(~scanf("%d",&q))
{
int flag=0;
if(q>=10000)
{
q=q-10000;
flag=1;
}
if(q<0) continue;
if(flag)
{
for(int i=1;i<=5;i++)
{
num[++n]=q;
}
}
else
num[++n]=q;
}
if(n==0)
{
printf("0\n");
return 0;
}
int now=1;
a[1]=num[1];
for(int i=2;i<=n;i++)
{
if(num[i]>=a[now]) a[++now]=num[i];
else
{
int l=upper_bound(a+1,a+1+now,num[i])-a;
a[l]=num[i];
}
}
printf("%d\n",now);
}
本题AC代码提供者还是Mr_Treeeee,感谢Mr_Treeeee的AC代码,下面给出原代码链接:
http://blog.csdn.net/mr_treeeee/article/details/78078435
M.Frequent Subsets Problem(进制运算或者集合)
题目链接:https://nanti.jisuanke.com/t/17320
PS:看到这题,本来想说怎么感觉有点复杂,看来还是英文没读懂,晕,赛后一问,进制运算/集合,整个人都不好了,突然想打人。MMP
题意:
给你一个n和a。n代表数据里只有1-n值的数字。
给你m个集合,让你求出存在几个子集,他在这m个集合里出现的次数>=a*m。
我们先来看一下进制运算的想法。
因为n只到20,直接利用二进制的位运算暴力解决,1代表有该元素,0代表没有该元素
给出代码:
#include
using namespace std;
typedef long long ll;
int n;
double m;
stringstream ss;
string s;
int t;
int c[55];
int sum=0;
int main()
{
// freopen("data.txt","r",stdin);
ios_base::sync_with_stdio(false);
memset(c,0,sizeof(c));
getline(cin,s);
ss<>n>>m;
while(getline(cin,s))
{
ss.clear();
ss<while(ss >> t)
{
c[sum] |= ( 1<<(t-1) );
}
// cout <
sum++;
}
int xx = ceil(m*sum);
int ans = 0;
int maxx = (1<for (int i=1;i<=maxx;i++)
{
int ct = 0;
for(int j=0;jif((i&c[j])==i)
{
// cout <<(i&c[j])<<" "<
ct++;
}
}
// if(ct)cout<
if(ct>=xx) ans++;
}
cout<return 0;
}
该想法由chudongfang2015给出,感谢这位大佬的AC代码,下面给出链接:
http://blog.csdn.net/chudongfang2015/article/details/78082970
下面我们来看一下集合思想的做法:
一个一个找,找1,1如果可以作为答案,找1 2。1 2不行找1 3。1 2行就找1 2 3。
接着找2,2可以找2 3,2 3不行找2 4。
这样需要剪枝,找1的时候肯定只存在在某几个集合中,做一个标记,继续找下去只要在这几个集合中找就行了。再继续更新标记,范围会越来越少
给出代码:
#include
using namespace std;
int flag[55][22];
int ans;
int num,temp,n;
void work(int x,int aim[])
{
int nn=0;
int faim[55];
for(int i=1;i<=num;i++)
faim[i]=aim[i];
for(int i=1;i<=num;i++)
{
if(flag[i][x]&&faim[i])
{
faim[i]=1;
nn++;
}
else
faim[i]=0;
}
if(nn>=temp)
{
ans++;
for(int i=x+1;i<=n;i++)
{
work(i,faim);
}
}
}
int main()
{
double a;
scanf("%d %lf",&n,&a);
int d;
num=1;
while(~scanf("%d",&d))
{
char c;
scanf("%c",&c);
flag[num][d]=1;
if(c=='\n')
num++;
}
num--;
temp=ceil((double)num*a);
ans=0;
for(int i=1;i<=n;i++)
{
int aim[55];
for(int i=1;i<=num;i++) aim[i]=1;
work(i,aim);
}
printf("%d\n",ans);
return 0;
}
本题AC代码提供者还是Mr_Treeeee,感谢Mr_Treeeee的AC代码,下面给出原代码链接:
http://blog.csdn.net/mr_treeeee/article/details/78078435
以上就是ACM-ICPC2017年南宁网络赛的题目及其题解收集了,有些题目由于还没有找到题解,所以还是待补状态,等有大佬放在网上之后再进行编辑。感谢网上给出AC代码的大佬们。
今年的ACM网络赛估计没了,上海的EC不知道是不是没有网络赛,如果没有,那南宁是今年ACM网络赛的最后一场了。我们2018ACM见