北邮新生排位赛8解题报告
题目出的越来越水了
A. 游戏 2014新生暑假个人排位赛08
题目描述
小弱发明了一个好玩的游戏,游戏开始时给你一个凸多边形,这个多边形可以任意旋转,平移。让你造出一个正方形“容器”(足够大),容器的两边垂直,两边水平。用这个容器把这个多边形完全包含,且多边形有且只有一条边恰好与容器下边界重合(与外界相通),不同的边与外界相通代表不同的方案。现在让你判断是否有方案可以让这个多边形能够不掉下来。不掉下来要求是至少有一条边与容器之间存在压力(假设摩擦系数无穷大)。
如下图,左边会掉下来,右边不会掉下来。
输入格式
有多组数据。
对于每组数据,第一行是多边形点数n(3 <= n <= 1000),后面n行分别是这些点沿着多边形逆时针的二维坐标(xi, yi)(xi,yi的绝对值 <= 1000,输入数据精度精确到两位)。
输出格式
对每组数据输出有多少种方案可以使多边形不掉下来。
输入样例
3
0.00 0.00
2.00 0.00
1.00 1.00
3
0.00 0.00
1.00 0.00
2.00 1.00
4
0.00 0.00
4.00 0.00
3.00 2.00
1.00 2.00
输出样例
0
2
3
题目情况WA
第一次是因为没有把首尾相连的时候(某条边连着两个钝角这时候只用记一次)想明白,同时概念也还不明白,只是因为旁边的人开始敲题了而已
B. 小妹妹送快递 2014新生暑假个人排位赛08
题目描述
Mays王国的女王大人每天过着自由自在的生活,她最大的乐趣就是给邻国的帅气王子写信。但是最近,Mays王国的叔叔们变得很无聊,他们知道女王大人每次都把信委托给皇家小妹妹快递公司的小妹妹们,于是叔叔们给每一条路都设立了路障,只有小妹妹们给他们表演节目才会让小妹妹们过去。
在每一个路障,都有不同数量的叔叔,只有表演的小妹妹的数量不少与叔叔的数量的时候叔叔才会放她们过去。
为了节省开销,小妹妹快递公司希望派最少的小妹妹把女王大人的信件送到。请你告诉他们需要派几个小妹妹。
输入格式
输入第一行为数据组数T(T<=10),接下来T组数据,每组第一行为n,m,,2<=n<=10000,1<=m<=100000,表示Mays王国的道路由n个节点组成,接下来m行,每行一组u,v,c表示连接节点u,v的一条无向道路,且路障上有c个叔叔,1<=u,v<=n,0<=c<=100。女王大人和皇家小妹妹快递公司都在节点1,帅气的邻国王子住在节点n。
输出格式
每组数据输出一个数字,表示小妹妹快递公司最少需要派出的小妹妹数量。如果无论派出多少小妹妹都无法把信送到帅气的邻国王子手里,输出"shimatta!"。
输入样例
1
3 3
1 2 1
2 3 1
1 3 3
输出样例
1
赛后 WWWWA
赛中:没有想到spfa为0时也必须有个人去送信,答案>=1
赛后 1 "shimatta!\n"的叹号没打
2 fl=true初始化写顺手了
3 又忘了ans>=1了
4 并查集查是否成立出了问题,这里不能够只查a和b.否则间接连通出错
得到新姿势,感谢大神,大概就是把cost排序后,当连通必然是最小量
膜拜膜拜膜拜*n
spfa可以卡死....
#include <cstdio> #include <algorithm> using namespace std; const int MAXN=10001; const int MAXM=200002; int par[MAXN]; struct edge{ int from,to,cost; }e[MAXM]; int n,m; bool cmp(edge ed1,edge ed2){ return ed1.cost<ed2.cost?true:false; } int findpar(int a){ if(par[a]==a)return a; else return par[a]=findpar(par[a]); } bool same(int a,int b){ if(findpar(a)==findpar(b))return true; return false; } bool inver(int a,int b){ if(!same(a,b)){ par[findpar(b)]=findpar(a); } if(same(n,1))return true; return false; } int main(){ int t,tf,tt,tc; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){par[i]=i;} for(int i=0;i<m;i++){ scanf("%d%d%d",&tf,&tt,&tc); e[i].from=tf;e[i].to=tt;e[i].cost=tc; } sort(e,e+m,cmp); bool fl=false; for(int i=0;i<m;i++){ if(inver(e[i].from,e[i].to)){ printf("%d\n",e[i].cost==0?1:e[i].cost); fl=true; break; } } if(!fl)printf("shimatta!\n"); } return 0; }
C. 学姐点名 2014新生暑假个人排位赛08
题目描述
学姐辛辛苦苦准备了一次讲座,讲课的过程中学姐数了一下人数,发现居然少到了一个学弟,学姐很生气,下决心要把这个学弟找出来。学姐开始点名了,为了快一点签到,学姐点名的时候只点大家的学号。学姐说:“这么简单的统计,几行就可以搞定,帮我写个程序吧,超过500B的运行时间又在1ms以上的我不要”。
oj的功能出了点问题,内存判定没有效果,代码长度限制也没有效果。oj上显示超过528B的代码,比赛结束前时限直接调成1ms手工重新判定。(换句话说,本地代码大小超过500B的AC不算。)
输入格式
每组数据第一行一个数N,接下来N-1行每行一个数字表示学弟的学号。
多组数据,eof结束。
2组数据N为1000000
500组数据满足N不大于3000
1000组数据满足N不大于10
输出格式
输出没到的学弟的学号
输入样例
3
1
3
2
1
输出样例
2
2
明明没有爆long long,才10^14
#include <cstdio> #include <assert.h> int n,temp; int main(){ while(scanf("%d",&n)==1){ long long ans=((n&1)!=0?(n+1)/2:n/2); ans=ans*(n&1?n:n+1); while(n--&&n>0){ scanf("%d",&temp);ans-=temp; } assert(ans>0); printf("%d\n",(int)ans); } return 0; }
但是实际上可以用异或这样就不会爆了(明明本来就不该爆)
#include <cstdio> int main(){ int n,temp; while((scanf("%d",&n))==1){ int seg1=0,seg2=0; for(int i=1;i<=n;i++)seg1^=i; for(int i=1;i<n;i++){ scanf("%d",&temp); seg2^=temp; } printf("%d\n",seg1^seg2); } return 0; }
D. 解码锦标赛 2014新生暑假个人排位赛08
题目描述
明光村迎来了一年一度的盛世——解码锦标赛,有 2^N 次个队伍从世界各村赶来参与比赛,编号为 1 - 2^N。赛制为每一轮晋级一半队伍,按序号大小两两比赛,淘汰弱者。一轮结束后,所有的胜者进入下一轮,依旧是按顺序两两比赛。比如第一轮就是 1 vs 2, 3 vs 4 ... 2^N - 1 vs 2^N。在一旁围观的 Mays 学姐告诉你,N次比赛后的胜者是唯一的。现在你拿到了一份各个参赛队伍的对抗胜率表 win,为 2^N * 2^N 的矩阵, win[i][j] 为一位小数,代表i胜j的概率。
你能告诉 Mays 学姐最有可能获得世界冠军的是那支队伍吗?
输入格式
多组数据。每组第一行为 N ,N <= 8,接下来 N 行 N 列为对抗胜率矩阵。 保证 win[i][j] + win[j][i] = 1 (i != j)。 以 N=0 结束输入。
输出格式
对每组数据,输出胜率最大的队伍的序号。如果最大的两个概率相差不到 0.001,则认为胜率相等,输出序号最小者。
输入样例
2
0.0 0.1 0.2 0.3
0.9 0.0 0.4 0.5
0.8 0.6 0.0 0.6
0.7 0.5 0.4 0.0
2
0.0 0.8 0.1 0.4
0.2 0.0 0.2 0.6
0.9 0.8 0.0 0.3
0.6 0.4 0.7 0.0
0
输出样例
2
4
#include <cstdio> #include <cstring> using namespace std; const int maxm=1<<8; int n; int m; double p[maxm][maxm]; double dp[9][maxm]; int num[maxm]; int main(){ while(scanf("%d",&n)==1&&n){ m=1<<n; memset(dp,0,sizeof(dp)); for(int i=0;i<m;i++){ for(int j=0;j<m;j++)scanf("%lf",p[i]+j); } for(int i=0;i<m;i++)dp[0][i]=1; for(int i=1;i<=n;i++){ for(int j=1<<i;j<=m;j+=(1<<i)){ for(int k=j-(1<<i);k<j-(1<<(i-1));k++){ for(int l=j-(1<<(i-1));l<j;l++) { dp[i][k]+=p[k][l]*dp[i-1][l]*dp[i-1][k]; //printf("dp[%d][%d] %lf p[%d][%d] %lf dp[%d][%d] %lf\n",i,k,dp[i][k],k,l,p[k][l],i-1,l,dp[i-1][l]); } } for(int k=j-(1<<(i-1));k<j;k++){ for(int l=j-(1<<i);l<j-(1<<(i-1));l++) { dp[i][k]+=p[k][l]*dp[i-1][l]*dp[i-1][k]; //printf("dp[%d][%d] %lf p[%d][%d] %lf dp[%d][%d] %lf\n",i,k,dp[i][k],k,l,p[k][l],i-1,l,dp[i-1][l]); } } } //for(int j=0;j<m;j++)printf("dp[%d][%d] %lf\n",i,j,dp[i][j]); } double maxans=0; int maxi=0; for(int i=0;i<m;i++){ if(dp[n][i]-maxans>0.001){ maxans=dp[n][i]; maxi=i; } } printf("%d\n",maxi+1); } return 0; }
E. 田田的算数题 2014新生暑假个人排位赛08
题目描述
焦级长和田田玩算数。焦级长给田田一个数列ai,然后问田田第i项到第j项的数的和。
田田随手写了个简单的数据结构就搞定了。于是焦级长打算加大题目难度。
焦级长又添加了一个操作,即从第i项到第j项都按顺序加上一个等差数列的项
如从第2项到第4项加入一个首项为1,公差为3的等差数列即第2项+1,第3项+4,第4项+7,以此类推
于是田田写了半天又WA又T还RE了一炮,终于来求救你让你来写个程序帮他
输入格式
第一行为case数T
每个case第一行输入n,m,表示有数列长为n,有m个操作
之后n个数为ai即数列的初始数
之后m行为m个操作
第一个操作为插入
为1,l,r,x,d
1表示插入操作,l,r为数列的[l,r]会进行操作,等差数列的首项为x,公差为d
第二个操作为查询和
为2,l,r
2表示查询,l,r为求和的范围,即求al到ar的数列的和
T<=10
n,m<=10^5
ai,x<10^5,|d|<=100;
输出格式
每个查询输出一个值
输入样例
1
6 9
1 2 3 4 5 6
2 1 4
2 1 6
1 1 4 1 0
2 2 5
1 2 4 1 1
2 1 4
2 2 4
2 1 5
2 2 6
输出样例
10
21
17
20
18
25
29
线段树,这会儿还不会,今晚补上....也许吧
先补个平方分割
#include <cstdio> #include <algorithm> #include <cmath> #include <assert.h> #include <cstring> using namespace std; long long a[100001]; long long ax[2001]; long long ad[2001]; long long sum[2001]; int n,m,blen; int cflnum(int n){ if(n==1)return 1; return sqrt((double)n*log(n)+1e-6); } void add(int l,int r,int x,int d){ // int lnum=l%blen==0?l/blen:l/blen+1; // int rnum=(r+1)%blen==0?r/blen+1:r/blen; int lnum=l/blen+1;int rnum=r/blen; int ls=lnum*blen,rs=rnum*blen; int i; for(i=l;i<ls&&i<=r;i++){ a[i]+=x; sum[lnum-1]+=x; x+=d; } for(int in=lnum;in<rnum;in++){ ax[in]+=x; ad[in]+=d; x+=d*blen; } assert(r-rs<blen); if(i<=rs)for(i=rs;i<=r;i++){ a[i]+=x; sum[rnum]+=x; x+=d; } } void query(int l,int r){ long long ans=0; //int lnum=l%blen==0?l/blen:l/blen+1; //int rnum=(r+1)%blen==0?r/blen+1:r/blen; int lnum=l/blen+1;int rnum=r/blen; int ls=lnum*blen,rs=rnum*blen; int i; for(i=l;i<ls&&i<=r;i++){ ans+=a[i]; ans+=ax[lnum-1]; int mod=i%blen; ans+=mod*ad[lnum-1]; } for(int in=lnum;in<rnum;in++){ ans+=sum[in]; ans+=ax[in]*blen; ans+=ad[in]*(blen-1)*blen/2; } assert(r-rs<blen); if(i<=rs)for(i=rs;i<=r;i++){ ans+=a[i]; ans+=ax[rnum]; int mod=i%blen; ans+=mod*ad[rnum]; } printf("%lld\n",ans); } int main(){ int t; scanf("%d",&t); while(t>0&&t--){ scanf("%d%d",&n,&m); int allnum=cflnum(n); blen=n/allnum; assert(blen>0); memset(sum,0,sizeof(sum)); memset(ad,0,sizeof(ad)); memset(ax,0,sizeof(ax)); for(int i=0;i<n;i++){scanf("%lld",a+i);sum[i/blen]+=a[i];} for(int i=0;i<m;i++){ int op; scanf("%d",&op); assert(op==1||op==2); if(op==1){ int l,r,x,d; scanf("%d%d%d%d",&l,&r,&x,&d); add(l-1,r-1,x,d); } else { int l,r; scanf("%d%d",&l,&r); query(l-1,r-1); } } } return 0; }
卡在意料之外的地方了 也就是更新那里因为分开处理了落到桶外的情况结果造成整个查询区间都不在桶内的时候出重复的问题,之后就是变量名各种各种打错了