比赛链接:点击打开链接
自己太弱,只A了第一题。。。。。。
A题 水到没朋友。。。。
AC代码:
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<queue>
#include<set>
#define pi acos(-1.0)
#define eps 1e-8
typedef long long ll;
using namespace std;
int mi[50],mx[50],ans[50];
int d,sum;
int main()
{
int i;
scanf("%d%d",&d,&sum);
int mi_sum=0,mx_sum=0;
for(i=0; i<d; i++)
{
scanf("%d%d",&mi[i],&mx[i]);
mi_sum+=mi[i],mx_sum+=mx[i];
}
if(sum<=mx_sum && sum>=mi_sum)
{
printf("YES\n");
int rest = sum-mi_sum;
for(i=0; i<d; i++) ans[i]=mi[i];
for(i=0;i<d;i++)
{
if(rest ==0 ) break;
int tmp=mx[i]-mi[i];
if(rest>=tmp)
{
ans[i]=mx[i];
rest-=tmp;
}
else if(rest< tmp)
{
//if(ans[i])
ans[i]=mi[i] + rest;
rest=0;
}
}
for(i=0; i<d; i++)
{
printf("%d ",ans[i]);
}
printf("\n");
}
else printf("NO\n");
return 0;
}
B题 dp
读题的时候竟然忽略了只能向下或者向右走这个关键一步!!!!!!所以一开始想成dfs了。。。然后正好看到学长们这道题尝试了几次T了,就更加坚信这一错误观点了。。。(他们T的原因是数组元素中有0的情况没有考虑到)。后来发现了,但是一方面时间不够,另一方面对路径的记录有些凌乱。所以。。。你懂的。
这题实际上就是一道棋盘dp。求路径上的数相乘乘积3结果末尾0的个数最少。因为零由2*5得到。所以对于棋盘上的每一个数,要记录它包含多少个2和5。
动态转移方程为:dp[i][j]=min(dp[i][j-1],dp[i-1][j])。result=min(dp[n-1][n-1][0],dp[n-1][n-1][1])。这道题的trick在于棋盘上的数有可能为0。如果不特判,必然T。
另一个需要强化的就是路径的记录。开一个二维数组记录路径,最后将 符合的路径存放在一个一维数组中输出。
AC代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
typedef long long ll;
#define pi acos(-1)
#define eps 1e-6;
using namespace std;
const int inf=1<<28;
const int maxn=105;
int mp[1050][1050],dp[1050][1050][2],has_zero,zero_x,zero_y;///dp[0]表示5,dp[1]表示2;
char dir[1050][1050][2];
char way[3050];
void get_cnt(int num,int i,int j)
{
while(num % 5== 0 && num)
{
dp[i][j][0]++;
num/=5;
}
while(num % 2 ==0 && num)
{
dp[i][j][1] ++ ;
num/=2;
}
}
int main()
{
int n,i,j;
memset(dp,0,sizeof(dp));
has_zero=0;
scanf("%d",&n);
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
scanf("%d",&mp[i][j]);
if(mp[i][j]== 0)
{
has_zero=1;
zero_x=i,zero_y=j;
dp[i][j][0] = dp[i][j][1] = 1;
}
else get_cnt(mp[i][j],i,j);
}
}
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
for (int k = 0; k < 2; k++)
{
if (i == 0 && j == 0) continue;
if (i == 0)
{
dp[i][j][k] += dp[i][j-1][k];
dir[i][j][k] = 'R';
}
else if (j == 0)
{
dp[i][j][k] += dp[i-1][j][k];
dir[i][j][k] = 'D';
}
else
{
dp[i][j][k] += dp[i-1][j][k] < dp[i][j-1][k] ? dp[i-1][j][k] : dp[i][j-1][k];
dir[i][j][k] = dp[i-1][j][k] < dp[i][j-1][k] ? 'D' : 'R';
}
}
}
}
if(min(dp[n-1][n-1][0],dp[n-1][n-1][1])>1 && has_zero)
{
printf("1\n");
for (int i = 0; i < zero_x; i++) printf("D");
for (int i = 0; i < n-1; i++) printf("R");
for (int i = zero_x; i < n-1; i++) printf("D");
}
else
{
printf("%d\n",min(dp[n-1][n-1][0],dp[n-1][n-1][1]));
int k=1;
if(dp[n-1][n-1][0] < dp[n-1][n-1][1]) k=0;
int cnt=0;
int i=n-1,j=n-1;
while(i!=0 || j!=0)
{
way[cnt++]= dir[i][j][k];
if(dir[i][j][k]=='R') j--;
else if(dir[i][j][k]=='D') i--;
}
for(i=cnt-1; i>=0; i--) putchar(way[i]);
}
puts("");
return 0;
}
C题 一道模拟题 和五子棋差不多,变成了三子棋。难点在于要判断的情况太多了,其中,平局情况只有在两种棋子相加恰好等于9即无法再放棋子的时候,而不是无论如何放都不可能有一方赢的时候,这一点我考虑错了,所以一直在想怎么判断在棋子没填满的情况下判断是否是平局,显然是画蛇添足了。另外,我在做题的时候,判断太复杂,代码量很大,比赛结束后看了琦神代码才恍然大悟,我太弱了。
AC代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
typedef long long ll;
#define pi acos(-1)
#define eps 1e-6
using namespace std;
const int inf=1<<28;
const int maxn=105;
char mp[4][4];
int x_cnt,zero_cnt;
int win(int t)
{
char c;
int i,j;
if(t==0) c='X';
else c='0';
int cnt=0;
for(i=0; i<3; i++)
{
cnt=0;
for(j=0; j<3; j++)
{
if(mp[i][j]==c) cnt++;
}
if(cnt==3) return 1;
}
cnt=0;
for(j=0; j<3; j++)
{
cnt=0;
for(i=0; i<3; i++)
{
if(mp[i][j]==c) cnt++;
}
if(cnt==3) return 1;
}
cnt=0;
for(i=0; i<3; i++)
{
if(mp[i][i] == c) cnt++;
if(cnt==3) return 1;
}
cnt=0;
for(i=0; i<3; i++)
{
if(mp[i][2-i]==c) cnt++;
if(cnt==3) return 1;
}
return 0;
}
int check()
{
int a=win(0);
int b=win(1);
//puts("xxxxx");
if(a==1 && b==1) return 0;///0 illegal
if(a==1 && x_cnt==zero_cnt)
{
return 0;
}
if(b==1 && x_cnt==zero_cnt+1) return 0;
if(a==1) return 1;///first win;
if(b==1) return 2; ///second win
if(x_cnt+zero_cnt == 9) return 3; ///draw
if(x_cnt==zero_cnt) return 4; ///first
if(x_cnt==zero_cnt+1) return 5;///second
}
int main()
{
int i,j;
x_cnt=0,zero_cnt=0;
for(i=0; i<3; i++)
{
scanf("%s",mp[i]);
}
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
{
if(mp[i][j] == 'X') x_cnt++;
else if(mp[i][j] == '0') zero_cnt++;
}
}
int ans= check();
if((x_cnt>zero_cnt+1) || (x_cnt<zero_cnt)) printf("illegal\n");
else if(ans==0) printf("illegal\n");
else if(ans==1) printf("the first player won\n");
else if(ans==2) printf("the second player won\n");
else if(ans==3) printf("draw\n");
else if(ans==4) printf("first\n");
else if(ans==5) printf("second\n");
return 0;
}
D题
给定正多边形三点,求符合条件的面积最小的正多边形面积。
一道几何题。因为时间不够了,比赛时没有看。通过给定三点求出三角形三边长,根据余弦定理,求得三个角大小,根据正弦定理a/sin(A)=2r进而求得外接圆半径。求三角形三角所对应的圆心角x,y,z。若正n边形满足条件,则设t=2*pi/n,则x y z都应是t的整数倍,并且 x/t + y/t + z/t == n 。其面积为0.5*r*r*sin(t)*n。
AC代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
typedef long long ll;
#define pi acos(-1.0)
#define eps 1e-6
using namespace std;
const int inf=1<<28;
const int maxn=105;
double x[5],y[5];
double edge[5];
double sita[5];
double r,per_sita;
void get_edge()
{
edge[0]= sqrt((x[0]-x[1])*(x[0]-x[1]) + (y[0]-y[1]) * (y[0]-y[1]));
edge[1]= sqrt((x[0]-x[2])*(x[0]-x[2]) + (y[0]-y[2]) * (y[0]-y[2]));
edge[2]= sqrt((x[1]-x[2])*(x[1]-x[2]) + (y[1]-y[2]) * (y[1]-y[2]));
}
void get_sita()
{
sita[0] = acos((edge[1]*edge[1]+edge[2]*edge[2]-edge[0]*edge[0])/(2*edge[1]*edge[2]));
sita[1] = acos((edge[0]*edge[0]+edge[2]*edge[2]-edge[1]*edge[1])/(2*edge[0]*edge[2]));
sita[2] = acos((edge[1]*edge[1]+edge[0]*edge[0]-edge[2]*edge[2])/(2*edge[1]*edge[0]));
// cout<<sita[0]<<" "<<sita[1]<<" "<<sita[2]<<" "<<sita[0]+sita[1]+sita[2]<<"\n";
}
bool check(int n)
{
int sum=0;
for(int i=0; i<3; i++)
{
sum+=int((sita[i]+eps) / per_sita);
}
if(fabs(sum*per_sita-2*pi)<=eps) return true;
return false;
}
int main()
{
int i;
for(i=0; i<3; i++)
{
scanf("%lf%lf",&x[i],&y[i]);
}
get_edge();
get_sita();
r=edge[0]/sin(sita[0])/2;///求外接圆半径
for(i=0;i<3;i++) sita[i] *=2;
for(i=3; i<=100; i++)
{
per_sita = 2*pi / i;
if(check(i))
{
break;
}
}
double s = 0.5*r*r *sin(per_sita)*i;
printf("%.10lf\n",s);
return 0;
}
E题
给一个字符串,只由“(”,“)”和“?”组成.。问号处可填“(”或“)”。并给定使用左右括号所需的cost。求cost最小的匹配括号串。对于当前串,只要左括号的个数大于右括号就可以继续。如果不符合,就要将之前?处改为左括号。根据贪心思想,使用的?必然是a-b最小的那个,所以可以使用一个优先队列来实现。串访问完后,只要判断左括号的数量是否为0即可。
AC代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
typedef long long ll;
#define pi acos(-1)
#define eps 1e-6
using namespace std;
const int inf=1<<28;
const int maxn=55005;
struct node
{
int w,id;
node (int x,int y) :w(x),id(y) {} ;
bool friend operator <(node a,node b)
{
return a.w>b.w;
}
};
priority_queue <node > q;
char s[maxn];
int main()
{
scanf("%s",s);
int n=strlen(s),a,b,i;
int rest = 0;
ll cost=0;
for(i=0; i<n; i++)
{
if(s[i]=='(') rest++;
else if(s[i]==')') rest--;
else if(s[i]=='?')
{
s[i]=')';
scanf("%d%d",&a,&b);
cost+=b;
q.push(node(a-b,i));
rest--;
}
if(rest<0)
{
if(q.empty())
{
break;
}
else
{
node tmp=q.top();
q.pop();
s[tmp.id]='(';
cost+=tmp.w;
rest+=2;
}
}
}
if(rest) printf("-1\n");
else printf("%lld\n%s\n",cost,s);
return 0;
}