--打铁的废物
第一次打ACM省赛,心态爆炸,打铁而归,回来补题的时候发现自己就是一
A.Seventeen
1.用1到n之间的数加减乘得17即可输出 2.i + i-1 + i - 2 + i + 3 == 0 所以我们可以先写前4个然后递增即可 3.注意可以用括号 eg:(4) 因为没看清题wa在这上面了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 55;
int n;
string s[N];
int a[N];
int main()
{
cin>>n;
if(n < 4){
cout<<-1<<endl;
}else if(n==4){
cout<<"((1+4)*3)+2"<<endl;
}else{
s[0] = "(3*5)-(1*2)+4+";
s[1] = "1-2+3+4+5+6+";
s[2] = "(1*2)+3+4-5+6+7+";
s[3] = "(1*2)+3-4-5+6+7+8+";
a[0] = 5, a[1] = 6, a[2] = 7, a[3] = 8;
int t = (n - 5) % 4;
string ss = s[t];
for(int i = a[t] ; i < n; i += 4)
{
string r = to_string(i+1) + "-" + to_string(i+2) + "-" + to_string(i+3) + "+" + to_string(i+4) + "+";
ss += r;
}
for(int i = 0 ; i < ss.length()-1 ; i++)
{
cout<<ss[i];
}
}
return 0;
}
K.Coins
小范围进行dp,大范围由于A有17,19 所以全为A
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
ll t;
int n;
int a[N];
int b[N];
int a1[5] = {2,3,17,19};
int b1[5] = {5,7,11,13};
int main()
{
memset(a,0x3f,sizeof a);
memset(b,0x3f,sizeof b);
a[0] = 0 , b[0] = 0;
a[2] = 1 , a[3] = 1, a[17] = 1, a[19] = 1;
b[5] = 1 , b[7] = 1, b[11] = 1, b[13] = 1;
for(int i = 1 ; i <= 1000 ; i++)
{
for(int j = 0 ; j < 4 ; j++)
{
if(i - a1[j] > a1[0]){
a[i] = min(a[i] , a[i-a1[j]] + 1);
}
if(i - b1[j] > b1[0]){
b[i] = min(b[i] , b[i-b1[j]] + 1);
}
}
}
cin>>n;
while (n--)
{
cin>>t;
if(t > 1000){
cout<<"A"<<endl;
}else if(a[t] >= 0x3f3f3f3f && b[t] >= 0x3f3f3f3f){
cout<<"-1"<<endl;
}else if(a[t] < b[t]){
cout<<"A"<<endl;
}else if(a[t] > b[t]){
cout<<"B"<<endl;
}else {
cout<<"both"<<endl;
}
}
return 0;
}
E.Subsegments
时间复杂度(nlogn) 题意找一段连续子区间其乘积为x,所以我们每次将所有数相乘,并且每一次乘x,放进map中,a = sum * x,所以我们只需要看sum什么时候等于a,那么该段区间相乘就为x a[i] = 0 时需要重新计数,因为区间不能存在0 x == 0 区间只需要存在 0 即可
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MAXN 501000
int n;
LL a[MAXN],x;
const LL mod=998244353;
LL g[MAXN];
map<LL,LL> q;
int main()
{
cin>>n>>x;
q[x]++;
LL ans=0,sum=1; //个数以及当前的和的数目
for(int last=0,i=1;i<=n;i++)
{
cin>>a[i];
if(x)
{
if(a[i]){
a[i] %= mod;
sum = sum * a[i] % mod; //计算sum
g[i] = sum * x % mod;
ans += q[sum];
q[g[i]]++;
}else{
//a[i]为0,重新开始
sum = 1;
q.clear();
q[x]++;
}
}
else
{
if(!a[i])last=i; // x为0 a[i]只要为零,保证最后一个是0,随便取
if(last)ans+=(last);
}
}
cout<<ans;
return 0;
}
H.Counting
纯纯模拟题,注意每次移动要清空
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e3+10;
typedef pair<int,int> PII;
PII dg[N];
int a[N][N];
int n,m,k,t;
string s[N];
int ans = 0;
int main()
{
cin>>n>>m>>k>>t;
for(int i = 1 ; i <= k ; i++)
{
int x,y;
cin>>x>>y;
dg[i] = {x,y};
if(a[x][y]!=0){
ans+=a[x][y];
}
a[x][y]++;
}
for(int i = 1 ; i <= k ; i++)
{
cin>>s[i];
}
cout<<ans<<endl;
ans = 0;
for(int i = 0 ; i < t ; i++)
{
ans = 0;
for(int j = 1 ; j <= k ; j++)//更新这一秒的,防止和上一秒有重复
{
int x = dg[j].first , y = dg[j].second;
a[x][y] = 0;
}
for(int j = 1 ; j <= k ; j++) //从第一个到第k个人遍历
{
int x = dg[j].first , y = dg[j].second;
if(s[j][i] == 'R' && y < m) y++;
else if(s[j][i] == 'L' && y > 1) y--;
else if(s[j][i] == 'U' && x > 1) x--;
else if(s[j][i] == 'D' && x < m) x++;
if(a[x][y]!=0){
ans+=a[x][y];
}
dg[j] = {x,y};
a[x][y]++;
}
cout<<ans<<endl;
}
return 0;
}
J.Football Match
第一次做计算几何,大体思路就是按照图上旗子的比例,先建造一个长度不变,但ab垂直bc的矩形,然后根据a,b之间的夹角和90度的差距,进行左右旋转 数学公式:几何问题:正弦公式,余弦公式,五角星的小角为36度,大角为252度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e3+10;
const double PI = acos(-1.0);
struct point
{
double x,y;
};
int t;
point change(point a,point b,double angle){ //旋转
double len=sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
double jj;
//计算两点原本存在角度
if(abs(a.x-b.x)<=1e-6) jj=PI/2; //不存在斜率
else jj= atan((a.y-b.y)/(a.x-b.x));//计算角度 返回与x轴的夹角角度
if(b.x<a.x||(abs(a.x-b.x)<=1e-6&&b.y<a.y)) jj+=PI;
jj+=angle;
point ans;
ans.x=a.x+cos(jj)*len;
ans.y=a.y+sin(jj)*len;
return ans;
}
int main()
{
cin>>t;
while (t--)
{
point a,b;
cin>>a.x>>a.y>>b.x>>b.y;
double len = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
point bb;
bb.x = a.x;
bb.y = a.y + len;
//构建一个不倾斜的矩形,然后算旋转度数
point c,d;
c.x=bb.x+len/2*3;
c.y=bb.y;
d.x=a.x+len/2*3;
d.y=a.y;
//计算中心点
point o = {(a.x+c.x)/2,(a.y+c.y)/2};
//五角星的外接圆和内切圆
double R = len/20*6;//五角星的比例 //外接圆半径
double r = R*sin(PI*18/180)/sin(PI*126/180); //内切圆半径 大角252 小角36
//正弦定理 a / A = b / B a为边 A为角
//初始化五角星
point e[6],j[6];
double angle = PI/2; //初始90度
for(int i = 1 ; i <= 5 ; i++)
{
e[i].x=o.x+cos(angle)*R;
e[i].y=o.y+sin(angle)*R;
angle-=PI*72/180; //顺时针
}
angle = PI*3/2; //初始270度
for(int i = 1 ; i <= 5 ; i++)
{
j[i].x=o.x+cos(angle)*r;
j[i].y=o.y+sin(angle)*r;
angle-=PI*72/180; //顺时针
}
//设定旋转角 处理四种情况 在四个象限 以及三四象限交界处
if(abs(a.x-b.x)>1e-6) angle=atan((a.y-b.y)/(a.x-b.x)); //a和b有斜度
else angle = PI/2; // 跟开始重建矩形一样
if(b.x<a.x||(abs(a.x-b.x)<=1e-6&&b.y<a.y)) angle+=PI; //角度发生变化
angle -= PI/2; //旋转角
c=change(a,c,angle);
d=change(a,d,angle);
for(int i=1;i<=5;i++){
e[i]=change(a,e[i],angle);
j[i]=change(a,j[i],angle);
}
printf("%.8f %.8f ",c.x,c.y);
printf("%.8f %.8f ",d.x,d.y);
printf("%.8f %.8f ",e[1].x,e[1].y);
printf("%.8f %.8f ",j[4].x,j[4].y);
printf("%.8f %.8f ",e[2].x,e[2].y);
printf("%.8f %.8f ",j[5].x,j[5].y);
printf("%.8f %.8f ",e[3].x,e[3].y);
printf("%.8f %.8f ",j[1].x,j[1].y);
printf("%.8f %.8f ",e[4].x,e[4].y);
printf("%.8f %.8f ",j[2].x,j[2].y);
printf("%.8f %.8f ",e[5].x,e[5].y);
printf("%.8f %.8f\n",j[3].x,j[3].y);
}
return 0;
}
B.Minimum Expression
dp我的痛,要学python了该 题意:一个字符串,向里面加加号,问最小值是多少 段数越大,各段的位数越接近,值越小 dp(i,j) i表示1~i个字符加进来,j表示有j段的最小数字
k中i-len-2,i-len+2 (因为n/m后,所有字段的长度不全为len,而是在len长度左右徘徊)
所以这里的i-len的范围可以开大一点
dp(i,j) = min(dp(i,j) , dp(k,j-1) + int(s(k+1,i+1))) ; 用c的话会出现精度问题
n,m=map(int,input().split())
m=m+1 # m+1 段
s=" "+input()#空格
dp=[[-1 for j in range(1010)] for i in range(1010)] #初始化
len=n//m #向下取整
#i表示 j表示
dp[0][0]=0 # i 表示 到第几个字符 j表示该第几段
for i in range(1,n+1): #1到n
for j in range(1,min(i,m)+1): #i>m时最多形成m+1段
for k in range(i-len-2,i-len+2): #向前走多少距离
if k>=j-1 and k<i and dp[k][j-1]!=-1:
if dp[i][j]==-1 or dp[i][j]>dp[k][j-1]+int(s[k+1:i+1]): #第k+1个到i的数字 自动去前缀0
dp[i][j]=dp[k][j-1]+int(s[k+1:i+1])
print(dp[n][m])
明年继续加油吧