POJ1019
思路:
1. i属于哪个区间[10^(k-1),10^k-1], 也就是n那个区间有几位数
long long map[]={0,45,9045,1395495,189414495,(long long)(2E31-1)};
我另外写了个程序算出来的..汗
2. i<=map[k], 纸上算出来一个式子, 根据h可以得出map[k]某个区间里第h行的末尾是第n个digits, 比如
123..9899100
123..9899100101
123..9899100101102
123..9899100101102103
当h=4时(第4行), n等于([103的3]到开始[123的1]有多少位digits)
反过来可以由已知的n求出h
这个h不一定是整数, 但是由于函数n=f(h)是递增的, 所以根据h的整数位可以得出要求的digit在哪一行内
h=sqrt(2*n/k+(0.5+map2[k-1]/k)^2-0.5-map2[k-1]/k
map2[k]存放了 1234..k个9有多少位数
3. 根据行数算出要求的digit是哪一行的第几位, 现在问题简化成求123..9899100..这个数列中的第几位数, 很简单了
细节:
注意第2步中
开方下来h如果是整数需要特别判断一下, 我在这磨了好久.. 因为开始试图用(int)(h-0.00001)这种方式判断整数纠缠不清.. 非常傻. 就想不起来直接判断
(实验了一下math.h的sqrt()函数对于整数的开方没有误差25.0000开方就是5.0000, 可以直接if(5==5.0000)这样)
代码用C++WA G++AC, 不知缘何
// Calculate using another program to achieve the array; // i of 9,99,999,9999 #include <stdio.h> #include <math.h> long long pow10(long long n) { long long a; a=1; while(n--) a*=10; return a; } int main() { long long map[]={0,45,9045,1395495,189414495,(long long)(2E31-1)}; long long map2[]={0,9,189,2889,38889}; //how many digits does {1 2 3 4 ... 99...9} have long long N; long long n,k,x,l,number,result,digit,k_; double h; /* bool newline; FILE *fp; char tt; fp=fopen("E:\\a.out","wt"); l=0; */ scanf("%lld",&N); while(N--) { /* if(newline) fputc('\n',fp); newline=false; l++; */ scanf("%lld",&l); for(k=1;l>map[k];k++); n=l-map[k-1]; h=sqrt((double)2*n/k+(0.5+(double)map2[k-1]/k)*(0.5+(double)map2[k-1]/k))-0.5-(double)map2[k-1]/k; if(h==(long long)h) x=(long long)h; else x=(long long)h+1; /* if(h==x) newline=true; */ n=n-map2[k-1]*(x-1)-(x-1)*x/2*k; for(k_=1;map2[k_]<n;k_++); //area's number of digits n-=map2[k_-1]; number=pow10(k_-1)+(n-1)/k_; digit=k_-(n-1)%k_; result=number/pow10(digit-1)%10; printf("%lld\n",result); //fputc(result+'0',fp); } return 0; }
POJ 1015
最优化原理 Principle of Optimality, 马克一下有空看看
还有这个
DP算法是Google出来的.. 都是这个算法, 不重复发言了..
虽然AC了(125ms) 还是有个疑问, 为什么每次S(J)(辩控和)必须最大? 是不是有可能S(J)不是最大的情况下因为V(J)(辩控差)的原因正好可以选一个s[i]很大的人这样在后面的过程中S(J)反而更大, 而因为每次都取最优反而埋没了这个解呢… 事实证明这不可能, 但是为什么? 等等再想这个问题.. 马克一下
细节:
1. path我用了三维空间.. 每一个状态我附上了完整的路径, 省得每次找某人有没有被选中还要回溯搜一遍.
2. 众所周知..这个数组序号不可以是负的比较麻烦, 我加了 #define A(x) (x+400) 这样定义int f[21][A(401)]; 使用的时候很方便了 f[21][A(-400)] 即可 多打几个符号看着顺心, 我有检查强迫症, 总是+400我会很困扰的..
3. memset()一般只能把int初始化为0, 其实-1也可以的, 参考补码的知识, -1=0xff, int是4字节, 连一起是0xffffffff, 还是-1 =P
4.freopen(“in.txt”, “r”, stdin); freopen(“out.txt”, “w”, stdout); 有in文件可以用一下, 方便对比
代码: (这种东西真是只给自己看的..)
#include <stdio.h> #include <stdlib.h> #include <string.h> #define A(x) (x+400) #define MAX(x,y) (x>y?x:y) int sort_function(const void *a,const void *b) { return *(int *)a-*(int *)b; } int main() { int p[201],d[201],v[201],s[201]; int f[21][A(401)],path[21][A(401)][21]; int n,m; int N,i,j,k,l,h; int D,P; N=0; while(1) { scanf("%d %d",&n,&m); if(!n&&!m) break; N++; for(i=1;i<=n;i++) { scanf("%d %d",p+i,d+i); v[i]=p[i]-d[i]; s[i]=p[i]+d[i]; } memset(f,0xff,21*A(401)*sizeof(int)); //f[i][A(j)]=0xffffff=-1; //开始忘*sizeof(int)了, int占4字节, 导致m稍微大一点就出错 f[0][A(0)]=0; for(i=1;i<=m;i++) for(j=-i*20;j<=i*20;j++) for(k=MAX(-(i-1)*20,j-20);k<=j+20 && k<=(i-1)*20;k++) { if(f[i-1][A(k)]==-1) continue; for(l=1;l<=n;l++) { if(v[l]==j-k && f[i-1][A(k)]+s[l]>f[i][A(j)]) { for(h=1;h<=i-1;h++) if(path[i-1][A(k)][h]==l) break; if(h>i-1) { //这里有个细节, 开始我写的h==i,其实不一定 如果上面是for(h=2.. //h==2,i==1,直接跳出, 那么就不对了, 写成h<=i-1的补集最好, 严密一点 f[i][A(j)]=f[i-1][A(k)]+s[l]; path[i][A(j)][i]=l; for(h=1;h<i;h++) path[i][A(j)][h]=path[i-1][A(k)][h]; } } } } printf("Jury #%d\n",N); for(i=0;i<=20*m;i++) { if(f[m][A(i)]==-1&&f[m][A(-i)]==-1) continue; j=f[m][A(i)]>f[m][A(-i)]?1:-1; P=(i*j+f[m][A(i*j)])/2; D=f[m][A(i*j)]-P; printf("Best jury has value %d for prosecution and value %d for defence:\n",P,D); qsort((void *)(path[m][A(i*j)]+1),m,sizeof(int),sort_function); for(k=1;k<=m;k++) printf(" %d",path[m][A(i*j)][k]); printf("\n\n"); j=-1; i=400; } } return 0; }
你好,看到你在我网站上的留言,特来转转。
想用google.com的话直接google.com/ncr嘛……