一个多月前积分终于过了1700,现在1766分,于是只能参加Div1了。
这次是虚拟参加,两个小时,A肯定过了,然后看B题没什么思路,开始看C。
C的题意很简单,输出1-n的一个排列,使得前i个数的积模n各不相同,也就是0-n-1的一个排列。
显然数论相关的问题,也看不出需要什么明显的结论,就开始胡猜了:
1.只有n为素数时,才有解(4是特例,因此WA了一次);
2.当n为素数时,怎么构造,我直接假设前i个数的积依次为1,2,3,......,n-1,0;有了这个假设,只要扩展欧几里得就能算出原排列,但是问什么刚好不重不漏,就不知道了。
(看来我恶搞还是很厉害的,T_T,希望下周上海赛正常发挥,虽然强手如林。)
B题,比赛结束后去看代码,好像是DP,但是读别人的通过代码,没看懂T_T。
C题通过代码:(省略头文件)
typedef long long LL;
#define N 100000+5
typedef long long LL;
LL inv[N],a[N];
LL n;
bool prime(int n)
{
for (int i=2;i<=(int)sqrt(n);i++)
if (n%i==0) return false;
return true;
}
LL extended_gcd(LL a,LL b, LL &x, LL &y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
else
{
int gcd = extended_gcd(b, a % b, x, y);
int t = x;
x = y;
y = t - (a / b) * y;
return gcd;
}
}
int main()
{
//freopen("b.txt","r",stdin);
cin>>n;
bool flag=true;
if (prime(n)) {
puts("YES");
for (int i=1;i<=n-1;i++) {
LL x,y;
extended_gcd(i,n,x,y);
while (x<0) x+=n;
inv[i]=x;
}
a[1]=1;
printf("%d\n",a[1]);
for (int i=2;i<=n;i++) {
a[i]=inv[(inv[i]*(i-1))%n];
if (a[i]==0) a[i]=n;
printf("%d\n",a[i]);
//
if (a[i]<=0 || a[i]>n) flag=false;
}
}
else
if (n==4) printf("YES\n1\n3\n2\n4\n");
else puts("NO");
//cout<<flag<<endl;
return 0;
}