// Piotr Jagiełło // możliwe że to najgorsze co kiedykolwiek napisałem #include <cstdio> #include <algorithm> #include <cassert> #define MAKS 250010 #define FEST 1000000000000000000LL typedef long long int lld; using namespace std; lld granica[MAKS]; lld grantab[][2]={{69993,4},{10371,5},{2993,6},{1258,7},{667,8},{412,9},{283,10},{209,11},{163,12},{133,13},{112,14},{97,15},{85,16},{76,17},{69,18},{63,19},{59,20},{55,21},{51,22},{48,23},{46,24},{44,25},{42,26},{40,27},{39,28},{38,29},{36,30},{35,31},{34,32},{33,34},{32,35},{31,36},{30,38},{29,40},{28,42},{27,44},{26,47},{25,51},{24,55},{23,62},{22,71},{21,95},{0,400}}; lld f1[51][401]; lld f2[MAKS][25]; int wynik[MAKS]; int N; lld zaduzo=FEST+1; lld zero=0; lld& dajF(lld i, lld j) { if(j>i*(i-1)/2)return zero; if(j>i*(i-1)/4)j=i*(i-1)/2-j; if(j>=granica[i])return zaduzo; if(i<51)return f1[i][j]; return f2[i][j]; } int LD; int drz[MAKS*4]; int wezWolnego(int k) { if(drz[1]<k)return -1; int akt=1; while(akt<LD) { if(drz[akt*2]>=k)akt*=2; else { k-=drz[akt*2]; akt=akt*2+1; } } int zwr=akt-LD; drz[akt]=0; akt/=2; while(akt>=1) { drz[akt]=drz[2*akt]+drz[2*akt+1]; akt/=2; } return zwr; } int main() { lld n; lld ktory; scanf("%lld %lld",&n,&ktory); if((n%4)!=0 && (n%4)!=1) { puts("NIE"); return 0; } int pozG=0; for(lld i=n;i>=0;i--) { while(i<grantab[pozG][0])pozG++; granica[i]=grantab[pozG][1]; } lld k=n*(n-1)/4; int przesuniecie=0; int pozW=0; while(min(k,(n-1)*(n-2)/2 - k)>=granica[n-1]) { //printf("n: %lld, k: %lld, GRANICA: %lld\n",n,k,granica[n-1]); wynik[pozW++]= ++przesuniecie; n--; } //fprintf(stderr,"trzeba teraz znaleźć %lld-permutację o %lld inwersjach (granica: %lld)\n",n,k,granica[n-1]); //printf("przesuniecie: %d\n",przesuniecie); N=n; dajF(1,0)=1; for(int i=2;i<=N;i++) { lld suma=0; for(int j=0;j<granica[i];j++) { suma+=dajF(i-1,j); if(j-i>=0)suma-=dajF(i-1,j-i); dajF(i,j)=suma; //printf("%lld ",dajF(i,j)); } //puts(""); } //---- LD=1; while(LD<N+1)LD*=2; drz[LD]=0; for(int i=1;i<=N;i++)drz[LD+i]=1; for(int i=LD-1;i>=1;i--)drz[i]=drz[2*i]+drz[2*i+1]; //int obrotow=0; while(n>1) { //fprintf(stderr,"n: %lld, ktory: %lld ",n,ktory); bool ok=false; //lld tmp=0; for(int i=max(0LL,k-(n-1)*(n-2)/2);i<n && k-i>=0;i++) { //obrotow++; tmp++; // (i+1)-sza grupa z kolei //fprintf(stderr,"niech to szlag %lld %lld -> %lld\n",n-1,k-i,dajF(n-1,k-i)); if(dajF(n-1,k-i)>=ktory) { // wybierz (i+1)-szą wolną liczbę z kolei wynik[pozW++]=wezWolnego(i+1)+przesuniecie; k=k-i; ok=true; break; } else ktory-=dajF(n-1,k-i); //printf("sprobowalismy i:%d, ktory: %lld\n",i,ktory); } //fprintf(stderr,"tmp: %lld\n",tmp); if(!ok) { puts("NIE"); return 0; } n--; } //fprintf(stderr,"OBROTOW: %d",obrotow); if(k>0 || ktory!=1) { puts("NIE"); return 0; } // weź ostatniego wolnego wynik[pozW++]=wezWolnego(1)+przesuniecie; puts("TAK"); for(int i=0;i<pozW;i++)printf("%d ",wynik[i]); puts(""); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | // Piotr Jagiełło // możliwe że to najgorsze co kiedykolwiek napisałem #include <cstdio> #include <algorithm> #include <cassert> #define MAKS 250010 #define FEST 1000000000000000000LL typedef long long int lld; using namespace std; lld granica[MAKS]; lld grantab[][2]={{69993,4},{10371,5},{2993,6},{1258,7},{667,8},{412,9},{283,10},{209,11},{163,12},{133,13},{112,14},{97,15},{85,16},{76,17},{69,18},{63,19},{59,20},{55,21},{51,22},{48,23},{46,24},{44,25},{42,26},{40,27},{39,28},{38,29},{36,30},{35,31},{34,32},{33,34},{32,35},{31,36},{30,38},{29,40},{28,42},{27,44},{26,47},{25,51},{24,55},{23,62},{22,71},{21,95},{0,400}}; lld f1[51][401]; lld f2[MAKS][25]; int wynik[MAKS]; int N; lld zaduzo=FEST+1; lld zero=0; lld& dajF(lld i, lld j) { if(j>i*(i-1)/2)return zero; if(j>i*(i-1)/4)j=i*(i-1)/2-j; if(j>=granica[i])return zaduzo; if(i<51)return f1[i][j]; return f2[i][j]; } int LD; int drz[MAKS*4]; int wezWolnego(int k) { if(drz[1]<k)return -1; int akt=1; while(akt<LD) { if(drz[akt*2]>=k)akt*=2; else { k-=drz[akt*2]; akt=akt*2+1; } } int zwr=akt-LD; drz[akt]=0; akt/=2; while(akt>=1) { drz[akt]=drz[2*akt]+drz[2*akt+1]; akt/=2; } return zwr; } int main() { lld n; lld ktory; scanf("%lld %lld",&n,&ktory); if((n%4)!=0 && (n%4)!=1) { puts("NIE"); return 0; } int pozG=0; for(lld i=n;i>=0;i--) { while(i<grantab[pozG][0])pozG++; granica[i]=grantab[pozG][1]; } lld k=n*(n-1)/4; int przesuniecie=0; int pozW=0; while(min(k,(n-1)*(n-2)/2 - k)>=granica[n-1]) { //printf("n: %lld, k: %lld, GRANICA: %lld\n",n,k,granica[n-1]); wynik[pozW++]= ++przesuniecie; n--; } //fprintf(stderr,"trzeba teraz znaleźć %lld-permutację o %lld inwersjach (granica: %lld)\n",n,k,granica[n-1]); //printf("przesuniecie: %d\n",przesuniecie); N=n; dajF(1,0)=1; for(int i=2;i<=N;i++) { lld suma=0; for(int j=0;j<granica[i];j++) { suma+=dajF(i-1,j); if(j-i>=0)suma-=dajF(i-1,j-i); dajF(i,j)=suma; //printf("%lld ",dajF(i,j)); } //puts(""); } //---- LD=1; while(LD<N+1)LD*=2; drz[LD]=0; for(int i=1;i<=N;i++)drz[LD+i]=1; for(int i=LD-1;i>=1;i--)drz[i]=drz[2*i]+drz[2*i+1]; //int obrotow=0; while(n>1) { //fprintf(stderr,"n: %lld, ktory: %lld ",n,ktory); bool ok=false; //lld tmp=0; for(int i=max(0LL,k-(n-1)*(n-2)/2);i<n && k-i>=0;i++) { //obrotow++; tmp++; // (i+1)-sza grupa z kolei //fprintf(stderr,"niech to szlag %lld %lld -> %lld\n",n-1,k-i,dajF(n-1,k-i)); if(dajF(n-1,k-i)>=ktory) { // wybierz (i+1)-szą wolną liczbę z kolei wynik[pozW++]=wezWolnego(i+1)+przesuniecie; k=k-i; ok=true; break; } else ktory-=dajF(n-1,k-i); //printf("sprobowalismy i:%d, ktory: %lld\n",i,ktory); } //fprintf(stderr,"tmp: %lld\n",tmp); if(!ok) { puts("NIE"); return 0; } n--; } //fprintf(stderr,"OBROTOW: %d",obrotow); if(k>0 || ktory!=1) { puts("NIE"); return 0; } // weź ostatniego wolnego wynik[pozW++]=wezWolnego(1)+przesuniecie; puts("TAK"); for(int i=0;i<pozW;i++)printf("%d ",wynik[i]); puts(""); } |