高一下二调2
$T1 \qquad $ 排座位
https://tg.hszxoj.com/contest/992/problem/4
$\quad \ \ $ 很难说,开始一眼暴力\(O(n^2)\)(好像不是),再看\(n=1e5\),废了,更不行了。但想起来归并排序,然而并不是归并排序。也是水过样例了,十分……
$T2 \qquad $ 梦中的学校
https://tg.hszxoj.com/contest/992/problem/2
$\quad \ \ $一眼直接变身半糖小子,梦中的梦中……梦中人的梦中,梦不到被吹散,往事如风……空空的天空……
不犯病了(doge)
点击查看图片
$\quad \ \ $算是个DP?记忆化搜索?总之考试的时候没想出来(还爆零了)。
$T3 \qquad $ 激突冲击
https://tg.hszxoj.com/contest/992/problem/3
$\quad \ \ $就是糖果原题,输入输出都没变。
偷一下 zby $tarjan$缩点代码
#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(){
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;
}
我 $spfa$ 乱卡常过的代码
#include<bits/stdc++.h>
using namespace std;
const int N=150050;
int nx[N<<1],to[N<<1],w[N<<1];
int dis[N],f[N],i,n,m,x,y,k,h[N],t,flag;
long long ans;
inline bool check(int k,int x,int y){
if((k==2||k==4)&&x==y)return false;
return true;
}
void add(int x,int y,int z){
to[++t]=y;
nx[t]=h[x];
h[x]=t;
w[t]=z;
}
int vis[N],q[N<<2],l,r;
inline void spfa(){
q[++r]=0;
f[0]=1;
vis[0]=1;
while(l<r){
int x=q[++l];
f[x]=0;
for(register int i=h[x];i;i=nx[i]){
if(dis[to[i]]<dis[x]+w[i]){
dis[to[i]]=dis[x]+w[i];
vis[to[i]]++;
if(vis[to[i]]>=n){
flag=1;
return ;
}
if(!f[to[i]]){
q[++r]=to[i];
f[to[i]]=1;
}
}
}
}
return ;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
memset(dis,-0x7f,sizeof dis);
dis[0]=0;
for(i=1;i<=m;i++){
cin>>k>>x>>y;
if(check(k,x,y)){
if(k==1)add(x,y,0),add(y,x,0);
else if(k==2)add(x,y,1);
else if(k==3)add(y,x,0);
else if(k==4)add(y,x,1);
else if(k==5)add(x,y,0);
}else {
cout<<"-1";
return 0;
}
}
for(i=n;i>=1;i--)add(0,i,1);
spfa();
if(flag)puts("-1");
else {
for(i=1;i<=n;i++)ans+=dis[i];
cout<<ans;
}
return 0;
}
$T4 \qquad $ 奖学金
https://tg.hszxoj.com/contest/992/problem/4
$\quad \ \ $本来想打暴力的(虽然最后变成了暴力,T成80了),正解用优先队列预处理一下,再判断就行了。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define intl register int
const int N=1010000;
int n,m,need,su,sum,f[N],g[N],fee;
struct stu{
int ca,p;
}s[N];
bool cmp(stu x,stu y){return x.ca<y.ca;}
bool cp(stu x,stu y){return x.p<y.p;}
int r(){
int ans=0;bool f=0;char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0' && ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
return f?~ans+1:ans;
}
priority_queue<int>q;
signed main(){
freopen("money.in","r",stdin);
freopen("money.out","w",stdout);
n=r();need=r();fee=r();
for(intl i=1;i<=need;i++)s[i].ca=r(),s[i].p=r();
sort(s+1,s+1+need,cp);
int su=0;
for(intl i=1;i<=n;i++)su+=s[i].p;
if(su>fee){printf("-1");return 0;}
sort(s+1,s+1+need,cmp);
int o=n/2;
for(int i=1;i<=o;i++){
q.push(s[i].p);
sum+=s[i].p;
}
for(int i=o+1;i<=need-o;i++){
f[i]=sum;
if(s[i].p<q.top()){
sum-=q.top();
sum+=s[i].p;
q.pop();
q.push(s[i].p);
}
}
while(!q.empty())q.pop();
sum=0;
for(int i=need;i>=need-o+1;i--){
q.push(s[i].p);
sum+=s[i].p;
}
for(int i=need-o;i>=o+1;i--){
g[i]=sum;
if(s[i].p<q.top()){
sum-=q.top();
sum+=s[i].p;
q.pop();
q.push(s[i].p);
}
}
for(int i=need-o;i>=o+1;i--){
if(f[i]+g[i]+s[i].p<=fee){
printf("%d",s[i].ca);
return 0;
}
}
return 0;
}
$\quad \ \ $听说有人二分过了,非常不爽(因为我开始也想二分,后来否了,要不然可能不T)。看了看他们代码,发现他们代码满足条件就往右跳,反之往左跳。也是造了个 \(Hack\) 数据,在他们第一次往左跳的点右边设置了一个合法的点(也就是答案)。
$\quad \ \ $ 看着他们被卡的表情也是爽了(doge)