CSP膜你賽15
阿新 • • 發佈:2020-10-14
T1 遊戲
這篇題解差點咕掉
將一個裝備的兩個屬性連上邊
對於樹型聯通塊,只有最大的屬性值不能被選
對於存在環的聯通塊,每個屬性都可以被選
主流做法有兩種:
(1):並查集
每次將一個裝備的兩個屬性連到一個並查集
如果已經在一個並查集裡說明是環
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define rint register int using namespace std; const int maxn=1e6+5; int fa[maxn],size[maxn]; bool cir[maxn]; int Find(int x){return fa[x]==x ? x : fa[x]=Find(fa[x]); } int main(){ freopen("game.in","r",stdin); freopen("game.out","w",stdout); int n;scanf("%d",&n); for(rint i=1;i<=n+1;i++) fa[i]=i,size[i]=1; for(rint i=1;i<=n;i++){ int x,y; scanf("%d%d",&x,&y); if(Find(x)==Find(y)) cir[Find(x)]=1; else{ cir[Find(x)]=cir[Find(x)]|cir[Find(y)]; size[Find(x)]+=size[Find(y)]; fa[Find(y)]=Find(x); } } for(rint i=1;i<=n+1;i++){ if(!cir[Find(i)]){ if(size[Find(i)]==1) return printf("%d\n",i-1); else size[Find(i)]--; } } return 0; }
(2):二分圖
把兩個屬性跟這個裝備連邊,每次只能選一個屬性就是匹配的過程
注意不能每次都memset一下vis陣列,會起飛打個時間戳就行
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define rint register int using namespace std; const int maxn=1e6+5; int mat[maxn],vis[maxn],head[maxn],len; int Time,ans; struct Node{ int to,next; }e[maxn<<1]; void Add(int x,int y){ e[++len].to=y; e[len].next=head[x]; head[x]=len; } int Find(int u){ vis[u]=Time; for(rint i=head[u];i;i=e[i].next){ int v=e[i].to; if(vis[v]==Time) continue; vis[v]=Time; if(mat[v]==-1||Find(mat[v])){ mat[v]=u; return 1; } } return 0; } int main(){ freopen("game.in","r",stdin); freopen("game.out","w",stdout); memset(mat,-1,sizeof(mat)); int n;scanf("%d",&n); for(rint i=1;i<=n;i++){ int x,y;scanf("%d%d",&x,&y); Add(x+n,i);Add(y+n,i); } for(rint i=n+1;;i++){ Time=i; if(!Find(i)) break; ans++; } printf("%d\n",ans); return 0; }
非主流思路:
大力貪心,直接亂搞能過
T2 嘟嘟嚕
約瑟夫問題
線性求解顯然不能過,思考優化
我們這時可以發現m很小,因此不是每輪操作都需要取模
於是可以把每次加m的操作改成乘法,減少操作次數
時間複雜度:O(能過)
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define rint register int using namespace std; int n,m; int main(){ freopen("mayuri.in","r",stdin); freopen("mayuri.out","w",stdout); int T;scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); int now=0,die=1; for(rint i=n-1;i>=1;i--){ if(n-i+1==m-1) break; die=m%(n-i+1); now=(die+now)%(n-i+1); } int len=n-m-1; if(m==2) len++; if(len<=0){ printf("%d\n",now+1); continue; } int last,x,ren=m; if(m==2) ren--; while(len){ last=ren-now; x=last/(m-1); if(len>=x){ len-=x; now+=x*m; ren+=x; } else{ now+=len*m; len=0; } if(len){ ren++; now=(now+m)%(ren+1); len--; } } printf("%d\n",now+1); } return 0; }
T3 天才紳士少女助手克里斯蒂娜
推柿子。
最後我們發現只關心x的平方,y的平方和x*y
線段樹或者樹狀陣列維護
當然線段樹常數較大,需要卡常卡好久
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define rint register int
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
const int mod=20170927;
int a[maxn],b[maxn];
int A,B,AB,ans;
struct Node{
int l,r;
ll ma,mb,mul;
}t[maxn<<2];
void pushup(int rt){
t[rt].ma=(t[rt<<1].ma+t[rt<<1|1].ma)%mod;
t[rt].mb=(t[rt<<1].mb+t[rt<<1|1].mb)%mod;
t[rt].mul=(t[rt<<1].mul+t[rt<<1|1].mul)%mod;
}
void Build(int rt,int l,int r){
t[rt].l=l;t[rt].r=r;
if(l==r){
t[rt].ma=1LL*a[l]*a[l]%mod;
t[rt].mb=1LL*b[l]*b[l]%mod;
t[rt].mul=1LL*a[l]*b[l]%mod;
return;
}
int mid=l+r>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
pushup(rt);
}
void modify(int rt,int pos,int v1,int v2){
if(t[rt].l==t[rt].r){
t[rt].ma=1LL*v1*v1%mod;
t[rt].mb=1LL*v2*v2%mod;
t[rt].mul=1LL*v1*v2%mod;
return;
}
int mid=t[rt].l+t[rt].r>>1;
if(pos<=mid) modify(rt<<1,pos,v1,v2);
else modify(rt<<1|1,pos,v1,v2);
pushup(rt);
}
void query(int rt,int l,int r){
if(l==r) return;
if(l<=t[rt].l&&t[rt].r<=r)
return A=(A+t[rt].ma)%mod,B=(B+t[rt].mb)%mod,AB=(t[rt].mul+AB)%mod,void();
int mid=t[rt].l+t[rt].r>>1;
if(l<=mid) query(rt<<1,l,r);
if(r>mid) query(rt<<1|1,l,r);
}
int main(){
freopen("kurisu.in","r",stdin);
freopen("kurisu.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(rint i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
Build(1,1,n);
int op,p,x,y;
for(rint i=1;i<=m;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&p,&x,&y);
modify(1,p,x,y);
}else{
A=0,B=0,AB=0;
scanf("%d%d",&x,&y);
query(1,x,y);
ans=(1LL*A*B%mod-1LL*AB*AB%mod+mod)%mod;
printf("%d\n",ans);
}
}
return 0;
}
T4鳳凰院凶真
單詞積累:phoenix 鳳凰
推薦補番:命運石之門
LCIS板子原來爺不會
翻了翻課件原來爺什麼都不會
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define rint register int
using namespace std;
const int maxn=5005;
int a[maxn],b[maxn],dp[maxn][maxn],pre[maxn][maxn];
void Print(int x,int y){
if(x==0) return;
Print(x-1,pre[x][y]);
if(dp[x][y]!=dp[x-1][pre[x][y]])
printf("%d ",b[y]);
}
int main(){
int n;scanf("%d",&n);
for(rint i=1;i<=n;i++) scanf("%d",&a[i]);
int m;scanf("%d",&m);
for(rint i=1;i<=m;i++) scanf("%d",&b[i]);
for(rint i=1;i<=n;i++){
int Max=0,k=0;
for(rint j=1;j<=m;j++){
dp[i][j]=dp[i-1][j];pre[i][j]=j;
if(a[i]>b[j]&&Max<dp[i-1][j])
Max=dp[i-1][j],k=j;
if(a[i]==b[j])
dp[i][j]=Max+1,pre[i][j]=k;
}
}
int ans=0;
for(rint i=1;i<=m;i++)
if(dp[n][i]>dp[n][ans]) ans=i;
printf("%d\n",dp[n][ans]);
Print(n,ans);
return 0;
}