这周末要打女生赛了,想着和队友练一场,在cf只找到2021年的,由于去年那场打过就不再打了,杭电oj上面最近的也是2019年的,就打了这场。不过题面真的是。。。一言难尽,tree那题题面说三棵树其实是一棵树,Tetris俄罗斯方块那题是道签到,题面input一行两个整数实际上是多行输入,一直以为思路错了卡了很久。。。。。。改成多行输入就对了。
ps:在这个页面交不了题,只能看题,在题库中对应题号是6544-6554.。
签到,只需记录当前共消费多少,每次买票时根据总消费加上打折的票价。
#include
const int maxn=1010;
using namespace std;
#define ll long long
double n,a[maxn];
int main()
{
double sum=0;
double res=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(sum<100)sum+=a[i];
else if(sum>=100&&sum<150)sum+=a[i]*0.8;
else if(sum>=150&&sum<400)sum+=a[i]*0.5;
else sum+=a[i];
}
printf("%.2lf\n",sum);
return 0;
}
将1-n的数分为两组,使得这两组数的gcd最大。
也是签到。
直接求1-n的和sum的第二大公因数,第一大公因数是sum本身,要分成两组数所以必不可能为sum,因此找第二大公因数。若a%x==0,b%x==0,则一定有(a+b)%x==0.只要其中一堆数和为第二大公因数即可。
#include
using namespace std;
typedef long long ll;
ll n;
int main(){
cin>>n;
ll sum=(1+n)*n/2;
int temp=1;
for(int i=2;i<=sqrt(sum);i++)
{
if(sum%i==0)
{
cout<
这题是学姐写的,没读题。
#include
using namespace std;
#define N 1000005
typedef long long ll;
struct node{int idx;ll x;ll val;};
bool operator < (node a,node b){return a.val>b.val;}
bool operator > (node a,node b){return a.val>n>>m;
priority_queue q;
ll ans=0;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
ans+=a[i]+b[i]+c[i];
q.push({i,1,3*a[i]+b[i]});
}
m-=n;
while(m--)
{
node t=q.top();q.pop();
ans+=t.val;
t.x=t.x+1;
t.val=2*a[t.idx]*t.x+a[t.idx]+b[t.idx];
q.push(t);
}
cout<
训练时没写出来,感觉是数据结构题,应该可以用线段树写,但是学的不精不会写。
赛后看了一下题解说是树链剖分板子题,马上去学了树链剖分,补了。
树链剖分+线段树维护。
n个节点n-1条边,保证无环,因此相当于是一棵树,任意两个节点之间的路径实际上只有一条,所以不需要计算最短路径。
原本每次修改区间上的节点可能会超时,但由于同个节点修改不超过10次之后节点权值最多只能是1,因此加一个maxx判断当前节点区间最大值,如果在修改时发现最大值为1那么就不需要再修改了,这样复杂度就不会超时。
#include
#define ll long long
const int N=1e5+10,M=N*2;
using namespace std;
inline ll max(ll a,ll b){return a > b ? a : b;}
int n,m,cnt,idx;
int id[N],nw[N],dep[N],sz[N],top[N],fa[N],son[N],w[N],h[N],e[M],ne[M];
//w[N]存节点权值,e[N],ne[N]邻接表存人数
//id[N]存节点dfs编号,nw[N]存每个编号(dfs)的权值,dep[N]存每个节点深度,sz[N]存以节点为根的子树大小
//top[N]存每个重链顶点,fa[N]存每个节点父节点,son[N]存每个节点重儿子,e[N]存边节点
struct tree
{
int l,r;
ll maxx,sum;
}tr[N*4];//线段树
void add(int a,int b)
{
//存边,更新邻接表
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
//dfs所有节点的重儿子,更新树节点信息
void dfs1(int u,int father,int depth)
{
dep[u]=depth,fa[u]=father,sz[u]=1;
for(int i=h[u];~i;i=ne[i])//遍历u邻接表
{
int j=e[i];
if(j==father) continue;//当前边节点为父节点
dfs1(j,u,depth+1);
sz[u]+=sz[j];//更新以u为根节点的子树大小;
if(sz[son[u]]>1;
build(u<<1,l,mid);build(u<<1|1,mid+1,r);
pushup(u);
}
//线段树进行修改并更新
void update(int u,int l,int r)
{
if(tr[u].maxx<=1)return;
if(tr[u].l==tr[u].r)//当前为叶子节点,更新
{
tr[u].maxx=sqrt(tr[u].maxx);
tr[u].sum=sqrt(tr[u].sum);
return;
}
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid&&tr[u<<1].maxx>1)update(u<<1,l,r);
if(r>mid&&tr[u<<1|1].maxx>1)update(u<<1|1,l,r);
pushup(u);
}
//线段树进行查询区间和
ll query(int u,int l,int r)
{
if(l<=tr[u].l&&r>=tr[u].r)return tr[u].sum;
int mid=tr[u].l+tr[u].r>>1;
ll res=0;
if(l<=mid) res+=query(u<<1,l,r);
if(r>mid) res+=query(u<<1|1,l,r);
return res;
}
//更新节点之间路径
void update_path(int u,int v)
{
while(top[u]!=top[v])//当两个节点的重链的头节点不一样,即不在一条重链上,优先走更低的重链
{
if(dep[top[u]]
这题代码也是学姐写的,没读题。
#include
using namespace std;
typedef long long ll;
#define N 1000005
ll n,m,cnt[N],ans=0,a,b;
int fa[N],color[N];
vector v[N];
map,ll> mp;
map mpp;
void dfs(int u,int f)
{
fa[u]=f;
if(color[u]==color[f]) cnt[u]++;
for(auto i:v[u])
{
if(i==f) continue;
mp[{u,color[i]}]++;
if(color[i]==color[u]) cnt[u]++,ans++;
dfs(i,u);
}
mpp.clear();
for(auto i:v[u])
{
ll x=mp[{u,color[i]}];
if(x>0) cnt[i]+=x-1;
mpp[color[i]]+=x;
}
map ::iterator it;
for(it=mpp.begin();it!=mpp.end();it++) ans+=it->second/2;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a);color[i]=a;
}
for(int i=1;i
没读题,应该也是签到,张钰敏写的,但是一开始好像pi精度没弄好wa了,学姐调了一下就过了。
#include
#include
using namespace std;
typedef long long ll;
const double pi=acos(-1);
int main()
{
int n;
while(cin>>n)
{
double xita=(2*pi)/n;//每个大扇形角度
double xita2=xita/2;
double ans=(n-1)*sin(xita)/2;
ans+=sin(xita2);
printf("%.6lf\n",ans);
}
return 0;
}
是一个分类讨论题。
时分秒针的每种组合都会代表两个时刻,因此对于给出的所有时刻我们都计算对应到0-12点时分秒针的组合,只需要计算总的秒数,排序。
由于我们可以进行两种操作,顺时针和逆时针,所以都求之后取最小值。
排序后找起始位置的左右两端的位置,计算差值,用走一圈的度数-差值,最小的即为答案。注意有可能会有和初始时刻重复的时间。
对于初始时刻排序后的位置分类讨论,如果排序后的初始位置在第一位,那么它左端为最后一个;
如果排序后的初始位置在最后一位,那么它左端为第一个。
一发过了,很开心。
#include
const int maxn=9e4;
const int lsum=43200;
using namespace std;
typedef long long ll;
int n;
int h,m,s;
int a[maxn];
int ar,cnt;
double ans;
int suan(int h,int m,int s)
{
int res=h*60*60+m*60+s;
if(res>=lsum)return res%lsum;
else return res;
}
int main()
{
cin>>n;
cin>>h>>m>>s;
a[0]=suan(h,m,s);
ar=a[0];
cnt=0;
for(int i=1;i<=n;i++)
{
cin>>h>>m>>s;
a[i]=suan(h,m,s);
if(a[i]==ar)cnt++;//标记有几个初始时刻
}
sort(a,a+1+n);
int temp=0;
for(int i=0;i<=n;i++)
{
if(a[i]==ar)
{
temp=i;
break;
}
}
int x=0,y=0;
if(cnt==n)cout<<"0.00"<
这题也是学姐写的。
七巧板画线,第一次画线多六块,往后每次画线增加的都是之前增加的块数加1;
即:
0:7
1:7+6
2:7+6+7
3:7+6+7+8
......
#include
using namespace std;
typedef unsigned long long ll;
ll n,t;
int main(){
while(cin>>n)
{
cout<<7+6*n+((n-1)*n)/2<
n,m<=12,范围很小,手画了几个感觉只有当n,m是4的倍数时才可以刚好填满。
猜测样例给的4x4是能组成的最小块。
当n,m是4的倍数时,k1=n/4,k2=m/4;输出k1*k2个最小块即可。
注意该题在杭电oj上是多个样例输入。
#include
using namespace std;
typedef long long ll;
char a[10][10];
int main()
{
int n,m;
a[1][1]='1',a[1][2]='1',a[1][3]='1',a[1][4]='3';
a[2][1]='2',a[2][2]='1',a[2][3]='3',a[2][4]='3';
a[3][1]='2',a[3][2]='2',a[3][3]='4',a[3][4]='3';
a[4][1]='2',a[4][2]='4',a[4][3]='4',a[4][4]='4';
while(cin>>n>>m)
{
if((n%4==0)&&(m%4==0))
{
int aa=n/4;
int bb=m/4;
for(int i=1;i<=aa;i++)
{
for(int h=1;h<=4;h++)
{
for(int j=1;j<=bb;j++)
{
for(int w=1;w<=4;w++)cout<