这几天失眠时间都不太够,室友太会折腾了,感觉有点累,所以昨天的题解也没写,看晚上能不能补起来。
B . Marbles
题意:给定N组数(xi,yi),玩家轮流操作,每次玩家可以选择其中一组对其操作,可以把它减去一个数,或同时减去一个数,当玩家操作后出现了(0,0)则胜利。
思路:注意这里是出现(0,0)胜,而不是全都是(0,0)胜,所以我们不能简单的球sg,最后异或得到答案。
但是我们转化一下,如果玩家面对的全是(1,2) 或(2,1),则他胜利,那么我们可以以这两个状态为起点得到sg函数,就转化为了nim博弈。 当然,前提是没有xi==yi的情况。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=210; int sg[maxn][maxn],vis[maxn]; void getsg() { rep(i,1,100) rep(j,1,100){ if(i==j) continue; memset(vis,0,sizeof(vis)); rep(k,1,min(i-1,j-1)) vis[sg[i-k][j-k]]=1; rep(k,1,i-1) if(i-k!=j) vis[sg[i-k][j]]=1; rep(k,1,j-1) if(i!=j-k) vis[sg[i][j-k]]=1; rep(k,0,10000) if(!vis[k]){ sg[i][j]=k; break; } } } int main() { int N,F=0,x,y,sum=0; getsg(); scanf("%d",&N); rep(i,1,N){ scanf("%d%d",&x,&y); sum^=sg[x][y]; if(x==y) F=1; } if(F||sum) puts("Y"); else puts("N"); return 0; }
C .Pizza Cutter
题意:对于一个匹萨,限制横着切N刀,竖着切M刀,问最后披萨被分为了多少块。 保证不存在超过三刀相交在一点的情况,以及在角上相交的情况。
思路:我们发现,一刀的贡献是与它相交的直线数+1。 横线和竖线的交点=N*M。 横线和横线的交点=逆序对数。竖线与竖线一样。
所以求两次逆序对即可。
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=2000010; struct in{ int x,y; bool friend operator <(in w,in v) { return w.x<v.x;} }s[maxn]; int sum[maxn],b[maxn],tot; void add(int a,int N){ for(int i=a;i<=N;i+=(-i)&i) sum[i]++; } int query(int a){ int res=0; for(int i=a;i;i-=(-i)&i) res+=sum[i]; return res; } ll get(int N) { sort(s+1,s+N+1); ll res=0; rep(i,1,N) sum[i]=0,b[i]=s[i].y; sort(b+1,b+N+1); tot=unique(b+1,b+N+1)-(b+1); rep(i,1,N) s[i].y=lower_bound(b+1,b+N+1,s[i].y)-b; for(int i=N;i>=1;i--){ res+=query(s[i].y); add(s[i].y,N); }return res; } int main() { int N,M; ll ans=0; scanf("%d%d",&N,&M); scanf("%d%d",&N,&M); rep(i,1,N) scanf("%d%d",&s[i].x,&s[i].y); ans=get(N); rep(i,1,M) scanf("%d%d",&s[i].x,&s[i].y); ans+=get(M); ans+=(ll)N*M+N+M+1; printf("%lld\n",ans); return 0; }
D .Unraveling Monty Hall
题意:统计不是1的个数。
思路:水题,就是题面太长。
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=2000010; int main() { int N,x,ans=0; scanf("%d",&N); rep(i,1,N) scanf("%d",&x),ans+=(x!=1); printf("%d\n",ans); return 0; }
E .Enigma
题意:给定字符串S,T,让T去匹配S,问有多少个匹配没有相同的字符。
思路:模拟。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1000010; char c[maxn],b[maxn]; int main() { int N,M,ans=0; scanf("%s%s",c+1,b+1); N=strlen(c+1); M=strlen(b+1); rep(i,1,N-M+1) { bool F=true; rep(j,1,M) if(b[j]==c[i+j-1]) F=false; ans+=(F); } printf("%d\n",ans); return 0; }
F .Music Festival
题意:有N个舞台(N<10),第i个舞台有Mi首歌(M总和<1000),给出每首歌的起始时间s,和终止时间t,以及价值val; 我们听完一首歌可以任意瞬移到另外的舞台,即不考虑时间边界。现在让你选择一种方案,使得每个舞台都至少听了一首歌,求最大价值。
思路:区间最值更新答案的,我们可以用线段树或者单调队列更新答案。这里用了线段树。 先离散化时间(2*N个),然后对于所有的节目,按起始时间排序(终止时间排序效果也一样),然后每次查询[1,s]的最大值,然后用结果去更新t点的值。 复杂度O(N^2*logN)。记录一个前缀最大值复杂度是O(N^2)的。
线段树:
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=1024; int dp[maxn][maxn],b[maxn<<1],cnt; bitset<maxn>S[maxn]; struct in{ int s,t,val,id; bool friend operator <(in w,in v){ return w.s<v.s; } }s[maxn]; struct Tree{ int Mx[maxn<<3]; void update(int Now,int L,int R,int pos,int val) { Mx[Now]=max(Mx[Now],val); if(L==R) return ; int Mid=(L+R)>>1; if(pos<=Mid) update(Now<<1,L,Mid,pos,val); if(pos>Mid) update(Now<<1|1,Mid+1,R,pos,val); } int query(int Now,int L,int R,int l,int r) { if(l<=L&&r>=R) return Mx[Now]; int Mid=(L+R)>>1,res=0; if(l<=Mid) res=max(res,query(Now<<1,L,Mid,l,r)); if(r>Mid) res=max(res,query(Now<<1|1,Mid+1,R,l,r)); return res; } }T[1024]; int main() { int N,M,tot=0,ans=0; scanf("%d",&N); rep(i,0,N-1){ scanf("%d",&M); rep(j,1,M){ tot++; scanf("%d%d%d",&s[tot].s,&s[tot].t,&s[tot].val); s[tot].id=i; b[++cnt]=s[tot].s; b[++cnt]=s[tot].t; } } sort(b+1,b+cnt+1); cnt=unique(b+1,b+cnt+1)-(b+1); sort(s+1,s+tot+1); M=(1<<N)-1; rep(i,1,tot) s[i].s=lower_bound(b+1,b+cnt+1,s[i].s)-b; rep(i,1,tot) s[i].t=lower_bound(b+1,b+cnt+1,s[i].t)-b; rep(i,1,tot) { dp[i][1<<s[i].id]=s[i].val; rep(j,1,M){ if(T[j].Mx[1]==0) continue; int Mx=T[j].query(1,1,cnt,1,s[i].s); if(Mx!=0) dp[i][j|(1<<s[i].id)]=max(dp[i][j|(1<<s[i].id)],Mx+s[i].val); } rep(j,1,M) { if(dp[i][j]) T[j].update(1,1,cnt,s[i].t,dp[i][j]); } ans=max(ans,dp[i][M]); } if(ans==0) ans=-1; printf("%d\n",ans); return 0; }
前缀最大值: (数组开小wa了一发)
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=1024; int dp[maxn][maxn],pre[maxn][maxn<<1],b[maxn<<1],cnt; struct in{ int s,t,val,id; bool friend operator <(in w,in v){ return w.s<v.s; } }s[maxn]; int main() { int N,M,tot=0,ans=0; scanf("%d",&N); rep(i,0,N-1){ scanf("%d",&M); rep(j,1,M){ tot++; scanf("%d%d%d",&s[tot].s,&s[tot].t,&s[tot].val); s[tot].id=i; b[++cnt]=s[tot].s; b[++cnt]=s[tot].t; } } sort(b+1,b+cnt+1); cnt=unique(b+1,b+cnt+1)-(b+1); sort(s+1,s+tot+1); M=(1<<N)-1; rep(i,1,tot) s[i].s=lower_bound(b+1,b+cnt+1,s[i].s)-b; rep(i,1,tot) s[i].t=lower_bound(b+1,b+cnt+1,s[i].t)-b; int pos=1; rep(i,1,tot) { while(pos<=s[i].s){ //更新前缀最大值 rep(j,1,M) pre[j][pos]=max(pre[j][pos-1],pre[j][pos]); pos++; } int t=1<<s[i].id; dp[i][t]=s[i].val; pre[t][s[i].t]=max(pre[t][s[i].t],s[i].val); rep(j,1,M) if(pre[j][s[i].s]) dp[i][j|t]=max(dp[i][j|t],pre[j][s[i].s]+s[i].val); rep(j,1,M) if(dp[i][j]) pre[j][s[i].t]=max(pre[j][s[i].t],dp[i][j]); ans=max(ans,dp[i][M]); } if(ans==0) ans=-1; printf("%d\n",ans); return 0; }
-----吃饭ing----
原文地址:https://www.cnblogs.com/hua-dong/p/10350608.html