(复习累了,写个blog放松下)
这场题目质量很高,可惜是在考试周打的,打的时候状态也不好,比赛时D想歪了(人麻了),E秒懂但感觉过于码农就一直在搞D,结果直接炸裂。。。
A. Stable Arrangement of Rooks(贪心+摸你)
我们很容易就能发现在(2k-1,2k-1)位置放下第k个车即为最优。
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1000005
#define mod 1000000007
using namespace std;
ll a[Ma];
int main()
{
ll tt;
scanf("%lld",&tt);
while (tt--)
{
ll n,k;
scanf("%lld%lld",&n,&k);
if ((n+1)/2<k)
printf("-1\n");
else
{
for (ll i=0;i<n;i++)
{
for (ll j=0;j<n;j++)
{
if (i/2+1<=k&&i%2==0&&i==j)
printf("R");
else
printf(".");
}
printf("\n");
}
}
}
return 0;
}
B. Integers Shop(贪心+思维)
这道题目题意有点绕,搞了半天才看懂 :(
首先讲下题目意思,首先对于前k个商店有数字[li,ri],价格为wi,里面所拥有的数字有[minl,maxr](其中minl=min(l1,l2.......,lk),maxr=max(r1,r2,......,rk) ),我们可以选择其中m个,购买的m个可获得的数字有
1.[li,ri]中所有数字
2.假设购买了第x,第y的商店数字,且rx<ly,可以获得[rx,ly]中所有数字
我们可以发现只要有出现minl与maxr就可以获得所有数字,因此所购买的商店最多有2个。
因此他的最小花费为买2个最优/买1个最优
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1000005
#define mod 1000000007
#define inf 2e9+7
using namespace std;
ll l[Ma],r[Ma],w[Ma];
int main()
{
ll tt;
scanf("%lld",&tt);
while (tt--)
{
ll n;
scanf("%lld",&n);
ll lw=inf,rw=inf,le=inf,re=0,mi=inf;
for (ll i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&l[i],&r[i],&w[i]);
if (le>l[i])
le=l[i],lw=w[i],mi=inf;
else if (le==l[i])
lw=min(lw,w[i]);
if (re<r[i])
re=r[i],rw=w[i],mi=inf;
else if (re==r[i])
rw=min(rw,w[i]);
mi=min(mi,lw+rw);
if (l[i]==le&&r[i]==re)
mi=min(mi,w[i]);
printf("%lld\n",mi);
}
}
return 0;
}
C. Hidden Permutations(交互+思维+链表)
这道题想了好久,也许是太久没训练了,也许也是链表熟练度还不够。
通过题目可以发现他的变换可以形成一个环形链表状物,例如:p1->p3->p5->p2->p1...
我们可以用n次操作找出其链表的样子,再用n次操作还原链表
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 10005
#define mod 1000000007
using namespace std;
ll ne[Ma],pre[Ma];
ll fi[Ma];
ll add[Ma];
ll f[Ma];
ll ask(ll x)
{
cout<<"? "<<x<<endl;
ll ans;
cin>>ans;
return ans;
}
int main()
{
ll tt;
cin>>tt;
while (tt--)
{
ll n;
cin>>n;
for (ll i=1;i<=n;i++)
fi[i]=ne[i]=0;
for (ll i=1;i<=n;i++)
{
ll p=ask(i);
for (ll j=1;j<i;j++)
add[j]=ne[add[j]];
while (!fi[p])
{
fi[p]=1;
ne[p]=ask(i);
p=ne[p];
for (ll j=1;j<i;j++)
add[j]=ne[add[j]];
}
add[i]=p;
}
for (ll i=1;i<=n;i++)
f[add[i]]=i;
cout<<"! ";
for (ll i=1;i<=n;i++)
cout<<f[ne[add[i]]]<<" ";
cout<<endl;
}
return 0;
}
D. The Winter Hike(思维+贪心+傻逼)
开题一看n<=250,立马往方向开搞,于是开搞BFS,最终光荣GG[博主是傻逼,大家千万不要学] :(
这道题意思就是要把[1,1]*[n,n]的朋友移动至[n+1,n+1]*[2n,2n],因此[n+1,n+1]*[2n,2n]的积雪无条件被扫掉,二对于[1,1]*[n,n]的朋友,我们可以将其压缩至一行/一列,因此只需扫除一个关键点就可以完成任务。
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1005
#define mod 1e18
using namespace std;
ll a[Ma][Ma];
int main()
{
ll tt;
scanf("%lld",&tt);
while (tt--)
{
ll n;
scanf("%lld",&n);
ll ans=0;
for (ll i=0;i<n*2;i++)
for (ll j=0;j<n*2;j++)
{
scanf("%lld",&a[i][j]);
if (i>=n&&j>=n)
ans+=a[i][j];
}
ll mi=min(min(min(a[n][0],a[0][n]),min(a[2*n-1][0],a[0][2*n-1])),min(min(a[n][n-1],a[n-1][n]),min(a[2*n-1][n-1],a[n-1][2*n-1])));
printf("%lld\n",ans+mi);
}
return 0;
}
E. New School(贪心+思维+sort)
这道题目很有意思,题目简洁明了,代码乱七八糟,思路很容易想,下手极难(动不动就o())
开始想的是用点更新线段树维护对错,然后写麻了(瞬间变成码农题),于是开始借鉴T神、jiangly等巨巨巨神的代码,最后因看不懂GG,最后自己静心想了大概1个多小时重整思路开做。
首先我们可以求出不踢学生的m组状态,而对于n个老师,我们只需取最大的m个(其余没用),
我们可以把m组学生的状态从小到大排序,并可以通过暴力判断第i组的学生有被删除的时候的最大
所能接受的值(复杂度o())。
而o()显然是我们不能接受的,但我们可以发现所能接受的值一定是老师的值/0,并且对于已经排序好的m组学生是递增的,因此可以优化到o()
显然暴力判断可以通过前缀和优化进行,因此得到最终结果o(m)
PS:感觉有点难讲清楚,还是需要大家思考下,可以对着代码看,如果还是不理解可以私信或者在评论区提问
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1000005
#define mod 1000000007
using namespace std;
ll tot[Ma],a[Ma],all[Ma];
ll ans[Ma];
vector <ll> b[Ma];
ll n,m;
ll cmp[Ma][3];
struct node
{
ll w,num,ne;
bool operator <(const node &A)const{
return w<A.w;
}
}t[Ma];
ll floor(ll x,ll y)
{
return (x-1)/y+1;
}
bool ask(ll x,ll y)
{
if (x<=y)
{
if (cmp[x-1][1]+cmp[y][0]-cmp[x][0]+cmp[m][1]-cmp[y][1]==m-1)
return 1;
else
return 0;
}
else
{
if (cmp[m][1]-cmp[x][1]+cmp[y-1][1]+cmp[x-1][2]-cmp[y-1][2]==m-1)
return 1;
else
return 0;
}
}
bool cmp1(node x,node y)
{
return x.num<y.num;
}
int main()
{
ll tt;
scanf("%lld",&tt);
while (tt--)
{
scanf("%lld%lld",&n,&m);
for (ll i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+n+1);
for (ll i=1;i<=m;i++)
a[i]=a[n-m+i];
for (ll i=1;i<=m;i++)
{
b[i].clear();
all[i]=0;
scanf("%lld",&tot[i]);
for (ll j=0;j<tot[i];j++)
{
ll x;
scanf("%lld",&x);
all[i]+=x;
b[i].push_back(x);
}
t[i]=(node){floor(all[i],tot[i]),i,0};
}
sort(t+1,t+m+1);
a[0]=0;
for (ll j=-1;j<=1;j++)
for (ll i=1;i<=m;i++)
{
if (t[i].w<=a[i+j])
cmp[i][j+1]=1;
else
cmp[i][j+1]=0;
cmp[i][j+1]+=cmp[i-1][j+1];
}
t[0].ne=0;
for (ll i=1;i<=m;i++)
{
t[i].ne=t[i-1].ne;
while (t[i].ne<m&&ask(i,t[i].ne+1))
t[i].ne++;
}
sort(t+1,t+m+1,cmp1);
for (ll i=1;i<=m;i++)
{
for (ll j=0;j<tot[i];j++)
if (floor(all[i]-b[i][j],tot[i]-1)<=a[t[i].ne])
printf("1");
else
printf("0");
}
printf("\n");
}
return 0;
}
总的来说没训练还是手生了,感觉水平下滑的有点大,F题一道分类讨论贪心题,感觉可写,等之后考试结束试试