A:HDU4861
描述:桌子上k个球,他们的权值分别是 (i=1,2,...,k) ball is 1^i+2^i+...+(p-1)^i (mod p),p是素数
两人轮流在剩下的中选一个拿,直到没有球,A是否拿的权值最多?
代码:
首先A先手,那么奇数个球,从小到大的顺序排依次拿,肯定是A赢
唯一的A不赢的可能性:每种价值的球都是偶数个,这样依次拿,两个人拿的就一样多了
一开始输出测试了很多组数据,发现直接看还是不好找规律啊,只要把赢的K,P输出来,就很容易看了
1 #include <iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #include <string.h> 5 using namespace std; 6 7 int k,p; 8 int a[104]; 9 //void solve(){ 10 // int ans=0; 11 // for(int i=1;i<=k;i++){ 12 // ans=0; 13 // for(int j=1;j<=p-1;j++){ 14 // ans+=(int)pow(j,i); 15 // } 16 // a[i]=(ans%p+p)%p; 17 // } 18 // for(int i=1;i<=k;i++){ 19 // cout<<a[i]<<" "; 20 // } 21 // cout<<endl; 22 //} 23 int main() 24 { 25 while(~scanf("%d%d",&k,&p)){ 26 // solve(); 27 int s=k/(p-1); 28 if(s%2==1) printf("YES ");else printf("NO "); 29 } 30 }
B:
描述:
代码:
C:
描述:
代码:
D:HDU4864
描述:N个机器,一个机器两个属性(时间x,等级y),M个任务(x,y),因为数据范围100*2<<1440,所以采取x大的先尽量满足的贪心策略,然后y大的先满足
int i=0,j=0;
while(i<M,i++){ while(j<N&&P1[j].l>=P2[i].l){ vis[P1[j].t]++; j++; } for(int t=P2[i].t;t<=100;t++){ if (vis[t]){ num++; vis[t]--; score+=500*P2[i].l+2*P2[i].t; break; } } }
代码:假设现在要完成i任务,现在我们把x大于等于i任务的机器都找出来,记录下来他们的y值,然后找到其中能做i任务的最小的y值即可,因为机器是x大的排在前面,保证了记录下来的机器的x一定大于后续的任务。
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #define LL long long 6 using namespace std; 7 8 int N,M; 9 struct Node{ 10 LL l,t; 11 bool operator<(const Node &X)const{ 12 if (l==X.l) return t>X.t; 13 else return l>X.l; 14 } 15 void print(){ 16 cout<<"l="<<l<<","<<"t="<<t<<endl; 17 } 18 }P1[100100],P2[100100]; 19 int vis[105]; 20 int main(){ 21 while(~scanf("%d%d",&N,&M)){ 22 LL l,t; 23 for(int i=0;i<N;i++){ 24 scanf("%I64d%I64d",&l,&t); 25 P1[i]=(Node){l,t}; 26 } 27 for(int i=0;i<M;i++){ 28 scanf("%I64d%I64d",&l,&t); 29 P2[i]=(Node){l,t}; 30 } 31 sort(P1,P1+N); 32 sort(P2,P2+M); 33 memset(vis,0,sizeof(vis)); 34 LL score=0,num=0; 35 int i=0,j=0; 36 for(;i<M;i++){ 37 while(j<N&&P1[j].l>=P2[i].l){ 38 vis[P1[j].t]++; 39 j++; 40 } 41 for(int t=P2[i].t;t<=100;t++){ 42 if (vis[t]){ 43 num++; 44 vis[t]--; 45 score+=500*P2[i].l+2*P2[i].t; 46 break; 47 } 48 } 49 } 50 printf("%I64d %I64d ",num,score); 51 } 52 return 0; 53 }
E:
F:
G:
H:
I:
HDU4869
【参考:http://blog.csdn.net/libin56842/article/details/38065951的证明】
描述:桌子上有M张扑克,进行N个操作,每个操作定义一个Xi,表示要把当点的扑克中的Xi翻一下,问最后可以有多少种情况?一开始所有牌都是朝下的(全0)。
代码:
又是一道机智题。首先,我们知道由于对称性,假设最后有K张牌朝上, 那么,这K张牌形成的可能性为C(M,K),与翻拍的过程没关系。
然后,因为牌只有01两种状态,所以假设sum=sigm(xi),sum为奇数,最后1的个数为奇数,否则为偶数。
if (l1>=x) l2=l1-x; else if (r1>=x) { if (l1%2==x%2) l2=0;else l2=1; }else l2=x-r1; if (r1+x<=M) r2=r1+x; else if (l1+x<=M) { if ((l1+x)%2==M%2) r2=M;else r2=M-1; }else r2=2*M-(l1+x); l1=l2,r1=r2;
然后问题就变成了到底最后有几个1的问题,参考别人的题解,是求出最少的1的个数,和最多的1的个数,因为奇偶性确定,从l到r每次增长1,但是,我觉得还不能证明为什么连续变化啊。还有就就求最小的1,因为当前01个数是唯一确定的,所以翻的情况是唯一确定的。
ans+=((F[M]%Mod)*(QuickMod(F[i]*F[M-i]%Mod,Mod-2)%Mod))%Mod;
F[i]=i!%Mod
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #define Mod 1000000009 6 #define LL long long 7 using namespace std; 8 9 int N,M; 10 LL F[100100]; 11 void builtF(){ 12 F[0]=1; 13 for(int i=1;i<=100000;i++){ 14 F[i]=(F[i-1]*i)%Mod; 15 } 16 return ; 17 } 18 LL QuickMod(LL a,LL p){ 19 LL ans=1; 20 while(p){ 21 if (p&1){ 22 ans=(ans*a)%Mod; 23 p--; 24 } 25 p>>=1; 26 a=(a*a)%Mod; 27 } 28 return ans; 29 } 30 int main(){ 31 builtF(); 32 while(~scanf("%d%d",&N,&M)){ 33 int l1=0,l2,r1=0,r2; 34 for(int i=0;i<N;i++){ 35 int x; 36 scanf("%d",&x); 37 if (l1>=x) l2=l1-x; 38 else if (r1>=x) { 39 if (l1%2==x%2) l2=0;else l2=1; 40 }else l2=x-r1; 41 if (r1+x<=M) r2=r1+x; 42 else if (l1+x<=M) { 43 if ((l1+x)%2==M%2) r2=M;else r2=M-1; 44 }else r2=2*M-(l1+x); 45 l1=l2,r1=r2; 46 } 47 LL ans=0; 48 for(int i=l1;i<=r1;i+=2){ 49 ans+=((F[M]%Mod)*(QuickMod(F[i]*F[M-i]%Mod,Mod-2)%Mod))%Mod; 50 } 51 printf("%I64d ",ans%Mod); 52 } 53 return 0; 54 }
J:【参考:http://www.cnblogs.com/chanme/p/3861766.html】
描述:注册两个账号打CF,给次选分低的账号打,赢一次+1,输一次-2,因为分数可能降低可能升高,所以就是一种随机转移的过程,抽象成马尔可夫过程。
dp[i]=dp[i+1]*p+dp[i-2]*q+1;
dp[i]表示从i的积分到20分的期望天数。
那么从后往前推的话。dp[i]=dp[i+1]*p+dp[i-2]*q+1;
1表示自己的本来状态。
考虑边界:dp[0]=dp[1]*p+dp[0]*q+1;所以dp[0]=1/p+dp[1]
dp[1]=dp[2]*p+dp[0]*q+1;所以dp[0]=1/p+1/p^2+dp[2]
依次我们可以顺序解出每个dp.
因为:dp[i]=dp[i+1]*p+dp[i-2]*q+1;
dp[i-1]=dp[i]*p+dp[i-3]*q+1;
dp[i]=dp[i-1]/p-dp[i-3]*q/p+1/p=(dp[i-1]-dp[i-3]*q+1)/p
每次计算等式右边的即可。
同时,要说明的就是
dp[20]=dp[20]*p+dp[18]*q+1;
dp[19]=dp[20]*p+dp[17]*q+1;
所以dp[20]=(dp[18]*q+1)/p
最后求sum就行了
代码:
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #define Mod 1000000009 6 #define LL long long 7 using namespace std; 8 9 double T[30]; 10 double p,ans,q; 11 int main(){ 12 while(~scanf("%lf",&p)){ 13 q=1-p; 14 ans=0; 15 T[0]=1/p;T[1]=T[0]/p;T[2]=T[1]/p; 16 ans+=T[0]+T[1]+T[2]; 17 for(int i=3;i<20;i++){ 18 T[i]=(T[i-1]-T[i-3]*q)/p; 19 ans+=T[i]; 20 } 21 ans=ans*2-T[19]; 22 printf("%.6lf ",ans); 23 } 24 return 0; 25 }
K: