题目链接
4 2 3 1 1 3 2 1 0 1 1 1 1 1 1 1 1 3 2 1 1 3 1 1 2 1 0 1 1 1 2 1 3 0
Case #1: 1 3 2 0题意:对于一个p进制的乘法表。现在将p进制的0,1,2....p-1映射成0到p-1的另一个排列,并且将乘法表0到p-1的相对顺序打乱。现在给你打乱以后的乘法表,让你求出每个数映射成了那个数?题解:解法很简单,但是不容易想到。首先0可以很容易确定出来,因为乘法表中只有0的那一行和那一列全是0。对于剩下的数字,1对于的那行十位只会出现0。对于2对应的那行,十位只会出现0,1,并且都会出现。那么对于i对应的那行,十位只会出现0,1,,,i-1,并且都会出现。简单的证明一下,对于第i行,十位最大是i*(p-1)那个数,显然是i-1,最小显然是0,由于i<p,所以对于0到i-1的每一个十位,都会出现。代码如下:(由于题目提示输入数据很多,所以用了输入输出优化)#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<vector> #include<cmath> #include<map> #define nn 550 using namespace std; pair<int,int> a[nn][nn]; map<int,int>ma; int p; bool use[nn]; inline int read() { char ch; bool flag=false; int re=0; while(!(((ch=getchar())>='0'&&(ch<='9'))||(ch=='-'))); if(ch!='-') { re*=10; re+=ch-'0'; } else flag=true; while((ch=getchar())>='0'&&(ch<='9')) { re*=10; re+=ch-'0'; } if(flag) re=-re; return re; } inline void write(int x) { if(x<0) { putchar('-'); x=-x; } if(x>=10) { write(x/10); } putchar(x%10+'0'); } int main() { int i,j; int cas=1; while(1) { p=read(); if(p==0) break; ma.clear(); for(i=0;i<p;i++) { for(j=0;j<p;j++) { a[i][j].first=read(); a[i][j].second=read(); } } printf("Case #%d: ",cas++); for(i=0;i<p;i++) { for(j=0;j<p;j++) { if(a[i][j].first!=a[i][j].second) break; if(j&&a[i][j]!=a[i][j-1]) break; } if(j==p) { ma[0]=i; break; } } int ix; for(i=0;i<p;i++) { if(ma[0]==i) continue; memset(use,false,sizeof(use)); for(j=0;j<p;j++) { use[a[i][j].first]=true; } ix=0; for(j=0;j<p;j++) { if(use[j]) ix++; } ma[ix]=i; } for(i=0;i<p;i++) { write(ma[i]); printf("%c",i==p-1?'\n':' '); } } return 0; }