2016年中国大学生程序设计竞赛(合肥)-重现赛(感谢安徽大学)(5/10)
1001: 传递要求 a->b->c && a->c
我的做法就是利用bitset预处理出x点可达点集,与可达到x点的点集
那么如何检验这个图是否传递;枚举完b和,枚举可达b点集中的点x,那么点x可达点集要包含c点集,这个利用bieset可以快速判断
整个做法就是(n^2)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<iostream> #include<sstream> #include<algorithm> #include<vector> #include<bitset> #include<set> #include<queue> #include<stack> #include<map> #include<cstdlib> #include<cmath> #define PI 2*asin(1.0) #define LL long long #define pb push_back #define pa pair<int,int> #define clr(a,b) memset(a,b,sizeof(a)) #define lson lr<<1,l,mid #define rson lr<<1|1,mid+1,r #define bug(x) printf("%d++++++++++++++++++++%d\n",x,x) #define key_value ch[ch[root][1]][0] const int MOD = 1000000007; const int N = 2016+15; const int maxn = 200+ 14; const int mm=100010; const int letter = 130; const int INF = 1e9; const double pi=acos(-1.0); const double eps=1e-8; using namespace std; 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*10+ch-'0';ch=getchar();} return x*f; } int T,n; char s[N][N]; bitset<N>vs[2][N],tt; int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%s",s[i]+1); for(int i=1;i<=n;i++) vs[0][i].reset(),vs[1][i].reset(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(s[i][j]=='P'){ vs[1][i][j]=vs[0][j][i]=1; } } } int flag=1; for(int x=1;x<=n;x++){ for(int i=1;i<=n;i++){ if(vs[0][x][i]){ tt=vs[1][i]&vs[1][x]; if(tt!=vs[1][x]){flag=0;break;} } } if(!flag) break; } if(!flag){ puts("N"); continue; } for(int i=1;i<=n;i++) vs[0][i].reset(),vs[1][i].reset(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(s[i][j]=='Q'){ vs[1][i][j]=vs[0][j][i]=1; } } } flag=1; for(int x=1;x<=n;x++){ for(int i=1;i<=n;i++){ if(vs[0][x][i]){ tt=vs[1][i]&vs[1][x]; if(tt!=vs[1][x]){flag=0;break;} } } if(!flag) break; } if(flag) puts("T"); else puts("N"); } return 0; }
1003:对于给定以x为根的游戏,我们把看看作是多条链的组合游戏(组合博弈)
那么一条链怎么赢?
我们以低位为接近根的边权:
00001:先手必赢 ,000010:先手必败
00011:先手必赢, 000100:先手必败………………
找到规律接近根的地方为1,先手必赢,否则必败
根据博弈组合游戏,那么答案就是包含x点的边权的异或和来判断先手是否能赢
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long ll; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e5+10, maxn = 1e3+20, inf = 2e9; struct edge { int v,w; int nex; }edge[N]; int head[N]; int edg; void init() { memset(head,-1,sizeof(head)); edg=0; } void add(int u,int v,int w) { edg++; edge[edg].v=v; edge[edg].w=w; edge[edg].nex=head[u]; head[u]=edg; } int main(){ int T; scanf("%d",&T); while(T--) { init(); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } while(m--) { int hh; scanf("%d",&hh); if(hh==0) { int x; scanf("%d",&x); int ANS=0; for(int i=head[x];i!=-1;i=edge[i].nex) { int w=edge[i].w; ANS^=w; } if(ANS) printf("Girls win!\n"); else printf("Boys win!\n"); } else { int u,v,w; scanf("%d%d%d",&u,&v,&w); for(int i=head[u];i!=-1;i=edge[i].nex) { if(edge[i].v==v) { edge[i].w=w; break; } } for(int i=head[v];i!=-1;i=edge[i].nex) { if(edge[i].v==u) { edge[i].w=w; break; } } } } } return 0; }
1005:
假设我们确定了前两列的状态,那么整个行列就可以O(n)推出来了
枚举状态就好了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e4+10, maxn = 1e3+20, inf = 2e9; const LL mod = 100000000+7; int n; char a[N]; int b[N]; LL cc(int x){ if(x==0||x==2) return 1ll; return 2ll; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s",a); n=strlen(a); for(int i=0;i<n;i++) a[i]-='0'; if(n==1){ if(a[0]==1) puts("2"); else if(a[0]==0||a[0]==2) puts("1"); else puts("0"); continue; } LL ans=0; for(int x=0;x<=min(2,(int)a[0]);x++){ ///printf("x = %d\n",x); LL sum=1; if(a[0]-x>2||a[0]-x<0) continue; b[0]=a[0]-x,b[1]=x; sum=sum*cc(b[0])%mod,sum=sum*cc(b[1])%mod; for(int i=2;i<n;i++){ b[i]=a[i-1]-b[i-1]-b[i-2]; if(b[i]<0||b[i]>2) {sum=0;break;} sum=sum*cc(b[i])%mod; } if(b[n-1]+b[n-2]!=a[n-1]) sum=0; ans=(ans+sum)%mod; ///printf("%d %d sum = %lld\n",a[0]-x,x,sum); } printf("%lld\n",ans); } return 0; }
1008:
n只有100,预处理n^2出每段区间的异或和
那么查询的时候就二分找最近的值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e5+10, maxn = 1e3+20, mod = 1e9+7, inf = 2e9; struct ss{ int value,c; }mp[N]; bool cmp(ss s1,ss s2) { if(s1.value == s2.value) return s1.c>s2.c; else return s1.value < s2.value; } int n,sum[N],a[N],cnt,san[N]; map<int,int > H; int main() { int T; scanf("%d",&T); while(T--) { cnt = 0; scanf("%d",&n); H.clear(); for(int i =1; i<=n; ++i) scanf("%d",&a[i]),sum[i]=sum[i-1]^a[i]; for(int i = 1; i <= n; ++i) { for(int j = i; j <= n; ++j) { if(H[sum[j]^sum[i-1]]) { mp[H[sum[j]^sum[i-1]]].c = max(j-i+1,mp[H[sum[j]^sum[i-1]]].c); } else { mp[++cnt].value = sum[j]^sum[i-1]; mp[cnt].c = j-i+1; H[sum[j]^sum[i-1]] = cnt; } } } sort(mp+1,mp+cnt+1,cmp); for(int i = 1; i <= cnt; ++i) { san[i] = mp[i].value; } int m,x; scanf("%d",&m); while(m--) { scanf("%d",&x); if(x <= san[1]) { printf("%d\n",mp[1].c); continue; } if(x >= san[cnt]) { printf("%d\n",mp[cnt].c); continue; } int pos1 = lower_bound(san+1,san+1+cnt,x) - san; int pos2 = pos1-1; if(abs(san[pos1]-x) < abs(san[pos2] - x)) { printf("%d\n",mp[pos1].c); } else if(abs(san[pos1]-x) > abs(san[pos2] - x)) printf("%d\n",mp[pos2].c); else printf("%d\n",max(mp[pos1].c,mp[pos2].c)); } printf("\n"); } return 0; }
1009:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pi (4*atan(1.0)) #define eps 1e-14 const int N=2e5+10,M=4e6+10,inf=1e9+10,mod=1e9+7; const ll INF=1e18+10; int a[110]; ll check(ll x) { int sum=0; while(x) { sum++; x/=2; } return sum; } int main() { int T; scanf("%d",&T); while(T--) { ll l,r; scanf("%lld%lld",&l,&r); int L=check(l); int R=check(r); if(L!=R) { printf("%lld\n",(1ll<<max(L,R))-1); } else { if(L==0) { puts("0"); continue; } int ps=L-1; int cnt=0; while((l&(1ll<<ps))==(r&(1ll<<ps))&&ps>=0){ a[++cnt]=(l&(1ll<<ps))>>ps; ps--; } for(int i=cnt+1;i<=L;i++) a[i]=1; ll ans=0; for(int i=1;i<=L;i++) ans=ans*2ll+1ll*a[i]; printf("%lld\n",ans); } } return 0; }