A:用一列放竖着的方块,两列放横着的方块。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 1010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n; char s[N]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif scanf("%s",s+1);n=strlen(s+1); int x=0,y=0; for (int i=1;i<=n;i++) if (s[i]=='0') { x++; if (x&1) cout<<1<<' '<<1<<endl; else cout<<3<<' '<<1<<endl; } else { y++;if (y>4) y=1; cout<<y<<' '<<2<<endl; } return 0; //NOTICE LONG LONG!!!!! }
B:先询问2k 2k+1,假设已经知道了a>2k,则当a>2k+1时,后者大,否则前者大。这样可以倍增出一个a的取值区间。注意到在区间内x mod a值开始单增,中间突变为0(即x=a),然后又单增,并且最开始的值要比最终的值大。于是拿2k+1和一个二分值比较即可。注意特判a=1的情况,询问0和1即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } char s[10]; signed main() { cin>>(s+1); while (s[1]!='e') { cout<<'?'<<' '<<0<<' '<<1<<endl; char c;cin>>c; if (c=='x') cout<<'!'<<' '<<1<<endl; else { int x; for (int i=0;i<30;i++) { cout<<'?'<<' '<<(1<<i)<<' '<<(1<<i+1)<<endl; cin>>c; if (c=='x') {x=i;break;} } int y=(1<<x+1); int l=(1<<x)+1,r=y-1,ans=y; while (l<=r) { int mid=l+r>>1; cout<<'?'<<' '<<mid<<' '<<y<<endl; cin>>c; if (c=='x') l=mid+1; else ans=mid,r=mid-1; } cout<<'!'<<' '<<ans<<endl; } cin>>(s+1); } return 0; //NOTICE LONG LONG!!!!! }
C:二选一当然是考虑问题间有什么关系。随便找一棵dfs树,如果深度>=n/k,那么显然有一条长度为n/k的简单路径;否则由抽屉原理,至少有一层的点数超过k,由此可得树的叶子数量超过k。注意到由于每个点度数至少为3,叶子至少会往上连两条边。我们考虑对每个叶子构造一个以其为标记的环。唯一的要求是环长不能为3的倍数,由于我们有至少两条边,所以可以得到至少三个包含该叶子的环,容易发现其中一定存在一个满足要求的。并且由于环长不会超过树的深度,所以总输出量也是O(n)的。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> #include<cassert> using namespace std; #define ll long long #define N 500010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,k,p[N],deep[N],fa[N],t,root=1; bool flag[N],isleaf[N]; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { flag[k]=1;int son=0; for (int i=p[k];i;i=edge[i].nxt) if (!flag[edge[i].to]) { deep[edge[i].to]=deep[k]+1; fa[edge[i].to]=k; son++; dfs(edge[i].to); } if (son==0) isleaf[k]=1; } signed main() { #ifndef ONLINE_JUDGE freopen("c.in","r",stdin); freopen("c.out","w",stdout); #endif n=read(),m=read(),k=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(); addedge(x,y),addedge(y,x); } deep[root]=1;dfs(root); for (int i=1;i<=n;i++) if (deep[i]>=n/k+(n%k>0)) { cout<<"PATH"<<endl;cout<<deep[i]<<endl; for (int x=i;x!=root;x=fa[x]) printf("%d ",x); cout<<root; return 0; } cout<<"CYCLES"<<endl; for (int i=1;i<=n;i++) if (isleaf[i]) { bool f=0; for (int j=p[i];j;j=edge[j].nxt) if (edge[j].to!=fa[i]&&(deep[i]-deep[edge[j].to])%3!=2) { printf("%d\n",deep[i]-deep[edge[j].to]+1); for (int x=i;x!=edge[j].to;x=fa[x]) printf("%d ",x); printf("%d\n",edge[j].to); f=1;break; } if (!f) { int u=0,v=0; for (int j=p[i];j;j=edge[j].nxt) if (edge[j].to!=fa[i]) if (!u) u=edge[j].to;else if (!v) v=edge[j].to; else break; if (deep[u]<deep[v]) swap(u,v); printf("%d\n",deep[u]-deep[v]+2); printf("%d ",i); while (u!=v) printf("%d ",u),u=fa[u]; printf("%d\n",v); } k--;if (k==0) break; } return 0; //NOTICE LONG LONG!!!!! }