• 2014 summer 多校1


    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 }
    View Code

    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 }
    View Code

    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个数是唯一确定的,所以翻的情况是唯一确定的。
    C(n,m) = n!/(m!*(n-m)!)     我们知道N,M是很大的,组合数无法直接计算
    但是我们知道费马小定理a^(p-1)=1%p         
    那么a^(p-1)/a = 1/a%p 得到 a^(p-2) =(1/a)%p
    发现了吧?这样就把一个整数变成了一个分母!
    那么上边的C(n,m)=n!*(1/(m!*(n-m)!)=n!=n!* (m!*(n-m)!)^(p-2)
    这样就把很大的1/n!求模,变成里快速幂。
     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 }
    View Code

    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 }
    View Code

    K:

  • 相关阅读:
    Out of hay
    P3028 [USACO10OCT]汽水机Soda Machine
    P3619 魔法
    P2847 [USACO16DEC]Moocast(gold)奶牛广播-金
    P2830 写程序
    c#DateTime与unix时间戳互相转换
    C# UdpClient使用
    udp单播,广播,多播实现(ReceiveFromAsync,SendToAsync)
    udp广播,单播,多播
    C#实现异步阻塞TCP(Send,Receive,Accept,Connect)
  • 原文地址:https://www.cnblogs.com/little-w/p/3866759.html
Copyright © 2020-2023  润新知