【比赛】高一下二调 2
事实证明打水题我还是有一手的
T1 排座位 100Pts
题面
算是个签到题。
直接暴力模拟,只要这个数不在自己的位置上就交换一次即可。
赛后题解中有另一种做法:
证明的话,数学奥赛的老师也没有具体的办法
抽象,但确实是对的。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;
int n,a[N],b[N],ans;
int main(){
freopen("seat.in","r",stdin);
freopen("seat.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[a[i]]=i;
}
for(int i=1;i<=n;i++){
if(a[i]!=i){
int tmp=a[i];
swap(a[i],a[b[i]]);
swap(b[tmp],b[i]);
ans++;
}
}
cout<<ans;
return 0;
}
T2 梦中的学校 40Pts
题面
记得 \(Huge\) 在第一次考试时说过一句话:
“这题是我们疫情时出的,为了防止你们上网查题解所以改了题面”
“但是你可以查输入输出数据”
所以这题其实是金字塔。
赛事看出来是 \(DP\) 了,但一直在想线性 \(DP\) ,遂假;
最后特判样例 \(+\) 两个答案为 \(0\) 的点 \(40\) 分
题解代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 310, mod = 1e9;
char str[N];
int f[N][N];
int main()
{
cin >> str + 1;
int n = strlen(str + 1);
if(n % 2 == 0) cout << 0 << endl;
else
{
for (int len = 1; len <= n; len += 2)
for (int l = 1; l + len - 1 <= n; l ++)
{
int r = l + len - 1;
if(len == 1) f[l][r] = 1;
else if(str[l] == str[r])
{
for (int k = l; k < r; k += 2)
if(str[k] == str[r])
f[l][r] = (f[l][r] + (ll)f[l][k] * f[k + 1][r - 1]) % mod;
}
}
cout << f[1][n] << endl;
}
return 0;
}
T3 激突冲击 100Pts
题面
其实是糖果。
赛时忘了正解怎么打了,也是因为懒得调,用迭代贪心水过了。
我就说我卡你们有用吧,除了 T1 就这题过的多
正解
#include<bits/stdc++.h>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m,op,x,y;
int dfn[N],low[N],num,cnt,size[N],id[N];
int f[N],in[N];
ll ans;
struct node{
int next,w;
};
vector<node> e1[N],e2[N];
bool vis[N];
stack<int> s;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*f;
}
void tarjan(int x){
dfn[x]=low[x]=++num;
vis[x]=1;
s.push(x);
for(auto &i:e1[x]){
int nx=i.next;
if(!dfn[nx]){
tarjan(nx);
low[x]=min(low[x],low[nx]);
}
else if(vis[nx]==1){
low[x]=min(low[x],dfn[nx]);
}
}
if(dfn[x]==low[x]){
int y;
cnt++;
do{
y=s.top();
s.pop();
id[y]=cnt;
size[cnt]++;
vis[y]=0;
}while(x!=y);
}
}
int main(){
freopen("bomb.in","r",stdin);
freopen("bomb.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;i++){
op=read();x=read();y=read();
switch(op){
case 1:
e1[x].push_back({y,0});
e1[y].push_back({x,0});
break;
case 2:
e1[x].push_back({y,1});
break;
case 3:
e1[y].push_back({x,0});
break;
case 4:
e1[y].push_back({x,1});
break;
default:
e1[x].push_back({y,0});
}
}
for(int i=1;i<=n;i++){
if(!dfn[i])tarjan(i);
}
for(int i=1;i<=n;i++){
for(auto &j:e1[i]){
int nx=j.next;
x=id[i],y=id[nx];
if(x==y&&j.w==1){
cout<<-1;
return 0;
}
if(x!=y){
e2[x].push_back({y,j.w});
in[y]++;
}
}
}
queue<int> q;
for(int i=1;i<=cnt;i++){
if(!in[i]){
q.push(i);
f[i]=1;
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(auto &i:e2[u]){
int nx=i.next;
in[nx]--;
f[nx]=max(f[nx],f[u]+i.w);
if(!in[nx])q.push(nx);
}
}
for(int i=1;i<=cnt;i++){
ans+=(ll)f[i]*size[i];
}
cout<<ans;
return 0;
}
迭代贪心法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*f;
}
struct order{
int t,a,b;
}e[N];
int n,m,c4[N];
int main(){
freopen("bomb.in","r",stdin);
freopen("bomb.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;i++){
e[i].t=read();e[i].a=read();e[i].b=read();
}
for(int i=1;i<=n;i++)c4[i]=1;
for(register int T=1;T<=1000;T++){
for(register int i=1;i<=m;i++){
if(e[i].t==1)c4[e[i].a]=c4[e[i].b]=max(c4[e[i].a],c4[e[i].b]);
else if(e[i].t==2)c4[e[i].b]=max(c4[e[i].b],c4[e[i].a]+1);
else if(e[i].t==3)c4[e[i].a]=max(c4[e[i].a],c4[e[i].b]);
else if(e[i].t==4)c4[e[i].a]=max(c4[e[i].a],c4[e[i].b]+1);
else c4[e[i].b]=max(c4[e[i].b],c4[e[i].a]);
}
}
for(register int i=1;i<=m;i++){
if(e[i].t==1){
if(c4[e[i].a]!=c4[e[i].b]){
cout<<-1;
return 0;
}
}
else if(e[i].t==2){
if(c4[e[i].a]>=c4[e[i].b]){
cout<<-1;
return 0;
}
}
else if(e[i].t==3){
if(c4[e[i].a]<c4[e[i].b]){
cout<<-1;
return 0;
}
}
else if(e[i].t==4){
if(c4[e[i].a]<=c4[e[i].b]){
cout<<-1;
return 0;
}
}
else{
if(c4[e[i].a]>c4[e[i].b]){
cout<<-1;
return 0;
}
}
}
ll ans=0;
for(int i=1;i<=n;i++){
ans+=c4[i];
}
cout<<ans;
return 0;
}
T4 奖学金 70Pts
题面
原题:洛谷 P3963。
思路清晰:从大到小枚举中位数,左右两边贪心找最小值,可行就直接 \(break\) 掉输出答案。
思路是清晰的,但三个 sort 毁了我的 AC 梦
算复杂度的时候只找了循环节,没看着 \(sort\) ,挂了 \(30\);
正解不需要 \(sort\) ,开优先队列扫即可,因为每次只有一个点出队和入队。
TLEのsort
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
struct pig{
ll score,money;
}a[N];
bool cmp1(pig a,pig b){
return a.score<b.score;
}
bool cmp2(pig a,pig b){
return a.money<b.money;
}
ll n,c,f;
int main(){
freopen("money.in","r",stdin);
freopen("money.out","w",stdout);
cin>>n>>c>>f;
for(int i=1;i<=c;i++){
scanf("%lld%lld",&a[i].score,&a[i].money);
}
ll sum=0;
sort(a+1,a+1+c,cmp2);
for(int i=1;i<=n;i++)sum+=a[i].money;
if(sum>f){
cout<<-1;
return 0;
}
int mid=(n+1)>>1,side=(n-1)>>1;
for(int i=c-mid+1;i>=mid;i--){
sort(a+1,a+1+c,cmp1);
int ans=a[i].score;
sort(a+1,a+i,cmp2);sort(a+i+2,a+1+c,cmp2);
sum=0;
for(int j=1;j<=side;j++){
sum+=a[j].money;
}
for(int j=i+1;j<=i+side;j++){
sum+=a[j].money;
}
sum+=a[i].money;
if(sum<=f){
cout<<ans;
return 0;
}
}
return 0;
}
优先队列(代码来自GGR)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define ps push_back
#define mk make_pair
#define fi first
#define se second
const int N=1e5+10;
struct jj{
int cj,w,id;
bool operator <(const jj&x){
return cj<x.cj;
}
}bi[N];
int a[N],n,c,ans;
ll f;
bool v[N];
priority_queue<pii >q2;
priority_queue<int> q1;
int main(){
freopen("money.in","r",stdin);
freopen("money.out","w",stdout);
cin>>n>>c>>f;
int k=n/2;
for(int i=1;i<=c;i++){
scanf("%d%d",&bi[i].cj,&bi[i].w);
}
sort(bi+1,bi+1+c);
ll l=0,r=0;
for(int i=1;i<=c;i++)bi[i].id=i;
for(int i=1;i<=k;i++){
q1.push(bi[i].w);
l+=bi[i].w;
}
for(int i=k+1;i<=c;i++){
q2.push(mk(-bi[i].w,bi[i].id));
}
for(int i=1;i<=k;i++){
r-=q2.top().fi;v[q2.top().se]=1;q2.pop();
}
for(int i=k+1;i<=c-k;i++){
if(i!=k+1&&bi[i-1].w<q1.top()){
l-=q1.top();l+=bi[i-1].w;
q1.pop();q1.push(bi[i-1].w);
}
while(!q2.empty()&&q2.top().se<=i)q2.pop();
if(v[i]){
r-=bi[i].w;r-=q2.top().fi;v[i]=0;v[q2.top().se]=1;q2.pop();
}
if(r+l+bi[i].w<=f){
ans=max(ans,bi[i].cj);
}
}
if(!ans){
cout<<-1;
return 0;
}
cout<<ans<<endl;
}
其实好像也可以用二分做,但我感觉没有单调性,于是赛时没打。
update:确实没单调性,被 Hack 掉了。
二分(代码来自教授)
#include<bits/stdc++.h>
using namespace std;
struct node1
{
long long mny,soe;
bool operator<(const node1 &A)const
{
if(mny==A.mny)
{
return soe>A.soe;
}
return mny<A.mny;
}
}pig1[200002];
struct node2
{
long long mny,soe;
bool operator<(const node2 &A)const
{
if(soe==A.soe)
{
return mny<A.mny;
}
return soe<A.soe;
}
}pig2[200002];
long long a,b,c;
inline bool check(long long x)
{
if(x<=a/2||x>b-a/2)
{
return false;
}
long long num1=0,num2=0,sm=0;
bool deng=false;
for(register long long i=1;i<=b;i++)
{
if(pig1[i].soe==pig2[x].soe&&deng==false)
{
sm+=pig1[i].mny;
if(sm>c)
{
return false;
}
deng=false;
continue;
}
if(pig1[i].soe<=pig2[x].soe&&num1<a/2)
{
num1++;
sm+=pig1[i].mny;
if(sm>c)
{
return false;
}
continue;
}
if(pig1[i].soe>=pig2[x].soe&&num2<a/2)
{
num2++;
sm+=pig1[i].mny;
if(sm>c)
{
return false;
}
continue;
}
}
return true;
}
int main()
{
freopen("money.in","r",stdin);
freopen("money.out","w",stdout);
scanf("%lld%lld%lld",&a,&b,&c);
for(register long long i=1;i<=b;i++)
{
scanf("%lld%lld",&pig1[i].soe,&pig1[i].mny);
pig2[i].soe=pig1[i].soe;
pig2[i].mny=pig1[i].mny;
}
sort(pig1+1,pig1+1+b);
sort(pig2+1,pig2+1+b);
long long m=1,n=b;
while(n-m>1)
{
long long l=(m+n)>>1;
if(check(l)==true)
{
m=l;
}
else
{
n=l;
}
}
if(check(n)==true)
{
printf("%lld",pig2[n].soe);
fclose(stdin);
fclose(stdout);
return 0;
}
if(check(m)==true)
{
printf("%lld",pig2[m].soe);
fclose(stdin);
fclose(stdout);
return 0;
}
puts("-1");
return 0;
}
后记
感谢 @GGR 送来的 rk1 。
GGR T1 把 ios::sync_with_stdio(false);
和 fclose(stdin);fclose(stdout);
混用导致爆零了;
T3 犯唐没开 long long
挂了 \(9\) 分;
都对他就 AK 了,感觉挺可惜的。
$\ $
这次出现了少见的 freopen
出错事件。
包括但不限于:
freopen("money.out","r",stdout);
freopen("bomb,out","w",stdout);
freopen("r", "bomb.in", stdin);
frepoen("school.in", "r", stdin);
$\ $
最后用 \(\text{Huge}\) 的一句话来结尾吧:
“难吗?这次考试和上次一样简单。”