A: 贪吃的zhazhahe

最开始的思路是假如5张饼4个空,就先2次搞好4个饼,再2次一个饼共4次,但显然错了,其实3次就可以,分别为1+,2+,3+,4+;5+,1-,2-,3-;4-,5-。问题出在最后有空但由于不能同时搞一张饼的两面而产生浪费,因此策略就是先尽量把所有饼的正面都搞好,再考虑反面。于是就产生了我下面的鬼畜代码,真的不堪入目。考虑了具体分配方法了,而题目只需要次数。。。

#include<iostream>
using namespace std;
 
int main()
{
    int t,n,k;
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        cout<<n/k+(bool)(n%k)+(n-(k-n%k)%k)/k+(bool)((n-(k-n%k)%k)%k)<<endl;
    }
    return 0;
}

后来看大佬的blog,发现直接把n个饼的2n个面连排,看成2n个面,比如5个饼:1+,2+,3+,4+,5+,1-,2-,3-,4-,5-。然后依次放就好了。结果就是2*n/k(整除时),或者2*n/k+1(不整除时)

自己又想了想,这两种都有漏洞,那就是若2*n<=k时,这时直接答案一定是2,事实上,n<=k时答案就是2.

B: 签到题

不知道为什么char数组就过了,而单字符和c++string都始终wa,太玄学了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
  
int main()
{
    int t;
    char n[505];
    cin>>t;
    while(t--)
    {
        scanf("%s",n);int len=strlen(n);
        int sum=0;
        for(int i=0;i<len;i++)sum+=n[i]-'0';
        cout<< (sum%3==0 ? "Three people are the most stable" : "Why would it be like this");
        cout<<endl;
    }
    return 0;
}

C: 算罚时

#include<iostream>
using namespace std;
 
int main()
{
     
    int t,a,b;
    cin>>t;
    while(t--)
    {
        int suma=0,sumb=0;
        for(int i=0;i<8;i++)scanf("%d:%d",&a,&b),suma+=a,sumb+=b;
        cout<<suma*60+sumb<<endl;
    }
    return 0;
}

D: 有趣的游戏

第一次做这种题,博弈论,其实题目初始给定的状态就决定了两人谁必胜谁必败,会有一个人无论多聪明也无法摆脱必败的定局。思想来自大佬的bloghttps://blog.csdn.net/bcwan_/article/details/53377375

    类型:博弈

    分析:这种类型题的基本思路是找到一种恒定不变的方式,使得对方无论怎么拿,你都能找到对应要拿的数量

          举个例子,假如n=22,取的区间为[1,2],那么小师妹第一次拿走1个,

          使得剩下的数量21,是区间左右端点之和的倍数,即3的倍数.

          那么无论对方怎么拿,我们都能维持剩下来的数量是3的倍数的状态不变,比如他拿1个,你就拿2个,或者他拿2个,你就拿1个

          始终保持他能拿,我必能拿的状态,那么只要判断初始情况,我就知道我能不能稳赢

          回顾刚刚的拿法,我们很容易推出一个方式判断第一个人应该如何拿,即余数=n%(L+R) 

          1.假设这个余数落在[L,R]里面,那么小师妹第一次把余数全抓走,剩下的是(L+R)的倍数,我们知道,小师妹稳赢       

          2.假设这个余数为L-k (0<k<=L)里面,那么因为只能抓[L,R]个珠子,小师妹动不了余数这个数目,她只能先动(L+R)里面合法的某些数目,那么第二个人能对应着拿掉小师妹在(L+R)里面剩下的数目,情况变成小师妹稳输         

          3.假设这个余数落在R+L-k (0<k<L)里面,那么小师妹第一次拿走R个,剩下的数目为L-k即把第二种状态丢给对方,小师妹稳赢

     所以题目可以解决.

  -----------------------------------------------------来自https://blog.csdn.net/bcwan_/article/details/53377375

#include<cstdio>
#include<iostream>
using namespace std;
 
int t,n,l,r;
 
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>l>>r;
        int ans=n%(l+r);
        if(ans>=l&&ans<=r)cout<<"Win\n";
        else if(ans<l)cout<<"Lose\n";
        else if(ans>r)cout<<"Win\n";
    }
    return 0;
}

E:套套套

嵌套矩形,先将所有矩形化为标准形式(a,b)其中a<=b,然后按a排序,若满足题意,则不存在两个矩形a相等,或a1<a2且b1>=b2。后来看大佬的blog,发现直接按面积排序也可以,如果满足题意,一定按面积从小到大满足前面的长宽分别小于后面的。

#include<iostream>
#include<algorithm>
using namespace std;
 
int t,n,x[10005],y[10005],d[10005];
bool cmp(int a,int b)
{
    return x[a]<x[b] ;
}
 
int main()
{   
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>x[i]>>y[i];
            if(x[i]>y[i])swap(x[i],y[i]);
        }
        bool ok=1;
        for(int i=1;i<=n;i++)d[i]=i;
        sort(d+1,d+1+n,cmp);
        for(int i=1;i<=n-1;i++)if(x[d[i]]==x[d[i+1]]||y[d[i]]>=y[d[i+1]]){ok=0;break;}
        printf(ok?"Yes\n":"No\n");
    }
    return 0;
}

F: 吃豆豆

算一个数的二进制表示有几个1。自己想的通过&1得到每一位的值,后来看dl的blog通过不断/2%2也可以实现。

#include<iostream>
using namespace std;
 
int main()
{
    long long a;
    while(scanf("%lld",&a)&&a!=-1)
    {
        int sum=0;
        for(int i=0;i<63;i++)if(((long long)1<<i)&a)sum++;
        cout<<sum<<endl;
    }
    return 0;
}

G: Pigofzhou和他的那么多个学妹

记录x页作为分界点的边界敲击次数,然后判断输入在哪个分界点的右边,然后就可以根据输入与边界的差轻松地算出具体是多少页。

#include<cstdio>
using namespace std;
 
int t;
long long a;
long long tot[15];
 
int main()
{
    tot[1]=9;
    for(int i=2;i<=13;i++)tot[i]=tot[i-1]*10;
    for(int i=1;i<=13;i++)tot[i]*=i;
    for(int i=2;i<=13;i++)tot[i]+=tot[i-1];
     
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&a);
        int pos=13;
        while(a<=tot[pos])pos--;
        long long last=(a-tot[pos])/(pos+1);
        long long num=1;
        for(int i=0;i<pos;i++)num*=10;
        num+=last-1;
        printf("%lld\n",num);
    }
    return 0;
}

H: 神奇的清华大大的神奇魔法

首先第一优先考虑不消耗魔法值,即尽量不改变字母,但注意改变字母顺序不消耗魔法值,因此字符串的先后序列不重要,只需要知道每个字符有多少个,在消耗魔法值尽可能少的前提下,按字典序依次输出各个字符数目的一半(因为是回文串,所以串的字典序完全取决于前一半)。对于长度为偶数,必须每个字符都有偶数个,奇数则只有一个字符奇数个,其余偶数个。具体思路实在懒得写了,见代码。

#include<cstdio>
using namespace std;
 
int t;
char s[200005];
int tot[26];
 
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        for(int i=0;i<26;i++)tot[i]=0;
        scanf("%s",s);
        for(int i=0;s[i];i++)tot[s[i]-'a']++;       
         
        for(int pos=0;pos<26;pos++)
        {
            if(tot[pos]%2)
            {
                for(int i=25;i>=pos;i--)if(tot[i]%2){tot[i]--;break;}
                tot[pos]++;
            }
        }
         
        for(int i=0;i<26;i++)if(tot[i])
        {
            for(int j=0;j<tot[i]/2;j++)printf("%c",'a'+i);
        }
        for(int i=0;i<26;i++)if(tot[i]%2)printf("%c",'a'+i);
        for(int i=25;i>=0;i--)if(tot[i])
        {
            for(int j=0;j<tot[i]/2;j++)printf("%c",'a'+i);
        }
        putchar('\n');
    }
    return 0;
}

I:神枪手TMK

不说了

J: 神龙的烦恼

按价格从小到大买就行了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
 
int n,m;
int num[100005],cost[100005],d[100005];
 
bool cmp(int a,int b)
{
    return cost[a]<cost[b];
}
 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d%d",&num[i],&cost[i]);
    for(int i=1;i<=n;i++)d[i]=i;
    sort(d+1,d+1+n,cmp);
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        if(m==0)break;
        ans+=min(m,num[d[i]])*cost[d[i]];
        m-=min(m,num[d[i]]);
    }
    cout<<ans<<"\n";
    return 0;
}