2016多校水题

多校水题

标签: 2016多校水题


多校3

1001

  • 官方题解

由于有(5)次的这个限制,所以尝试寻找分界点。

很容易发现是(2^{32}),所以我们先比较输入的数字是否比这个大,然后再暴力开根。

复杂度是(O(loglog n))

注意特判(n=0)的情况。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
char mm[110];
int main()
{
    while(~scanf("%s",mm))
    {
        int len = strlen(mm);
        if(len > 15) {
            puts("TAT");
            continue;
        }
        int cnt = 0;
        long long num = 0;
        for(int i = 0; i < len; i++){
            num = num*10+mm[i]-'0';
        }
        //printf("%d
",num);
        if(num==1){
            puts("1");
            continue;
        }
        bool fl = 0;
        while(num!=1){
            if(cnt>4) {fl = 1;break;}
            num = (long long)sqrt((double)num);
            cnt++;
        }
        if(fl==1) puts("TAT");
        else if(fl == 0 ){
        printf("%d
",cnt);
        }
    }
    return 0;
}

1002

  • 官方题解

根据期望的线性性,我们可以分开考虑每个位置对答案的贡献。

可以发现当(i)不在两边的时候和两端有六种大小关系,其中有两种是对答案有贡献的。

那么对答案的贡献就是(frac{c_i}{3})

在两端的话有两种大小关系,其中有一种对答案有贡献。

那么对答案的贡献就是(frac{c_i}{2})

复杂度是(O(n))

注意特判(n=1)的情况。

  • 我的做法

直接打表找规律的,哈哈

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1008;
double c[N];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i = 0; i < n; i++)
            scanf("%lf",&c[i]);
        if(n==1)
        {
            printf("%.6lf
",c[0]);
            continue;
        }
        else if(n==2)
        {
            printf("%.6lf
",(c[0]+c[1])/2);
            continue;
        }
        else
        {
            double lf = 0;
            for(int i = 0; i <n; i++)
            {
                if(i==0||i==n-1) lf = lf+c[i]/2;
                else lf = lf + c[i]/3;
            }
            printf("%.6lf
",lf);
        }
    }
    return 0;
}

1011

  • 官方题解

考虑一种暴力,每次枚举两两点对之间的曼哈顿距离,并开一个桶记录每种距离是否出现过,如果某次枚举出现了以前出现的距离就输 (YES) ,否则就输 (NO)

注意到曼哈顿距离只有 (O(M)) 种,根据鸽笼原理,上面的算法在 (O(M)) 步之内一定会停止.所以是可以过得.
一组数据的时间复杂度 (O(min{N^2,M}))

  • 我的理解

这个题利用了鸽巢原理,所以可以暴力


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 300004;
int xx[N],yy[N];
int vis[N];
int aabs(int a)
{
    if(a>=0) return a;
    else return -a;
}
int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        memset(xx,0,sizeof(xx));
        memset(yy,0,sizeof(yy));
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&m);
        int x,y;
        for(int i = 0; i < n; i++){
            scanf("%d%d",&xx[i],&yy[i]);
        }
        bool fl = 0;

        for(int i = 0; i <n&&fl==0; i++){
            for(int j = i+1; j < n&&fl==0; j++){
                int tm = aabs(xx[i]-xx[j])+aabs(yy[i]-yy[j]);
                if(vis[tm])  {
                    fl = 1;
                }
                else vis[tm] = 1;
            }
        }
        if(fl) puts("YES");
        else puts("NO");
    }
    return 0;
}

多校3题解

多校4

1001

  • 官方题解

对于这个问题,显然可以进行DP: 令dp[i]表示到i结尾的字符串可以表示的不同含义数,那么考虑两种转移: 末尾不替换含义:dp[i - 1] 末尾替换含义:dp[i - |B|] (A.substr(i - |B| + 1,|B|) = B) 那么对于末尾替换含义的转移,需要快速判断(B)能不能和当前位置的后缀匹配,kmp或者hash判断即可。 复杂度:O(N)

  • 我的做法

和去年一个多校题十分的像,考虑dp[i]表示扫描到i这个字符的时候得到了几种含义,那么有当前末尾字符替换含义和不替换含义,dp[i-1] 和dp[i-|B|]加起来就可以了
但是这个题我以为是考虑两个长度相同的子串是不是匹配,可以直接用string的函数或者是直接扫一遍就可以了,所以并没有用kmp或者是hash算是一个水水的题了、

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 100008;
char a[N],b[N];
ll dp[N];
const ll Mod = 1e9+7;
int main()
{
    int T;
    int cc = 1;
    scanf("%d",&T);
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%s",a+1);
        scanf("%s",b+1);
        int len1 = strlen(a+1);
        int len2 = strlen(b+1);
        //printf("%d %d
",len1,len2);
        dp[0] = 1;
        for(int i = 1; i <= len1; i++){
            dp[i] = dp[i-1];
            bool fl = 0;
            if(i>=len2){
                fl = 1;
                for(int j = 1; j <= len2; j++){
                    if(a[i-len2+j]!=b[j]) {
                        fl = 0;
                        break;
                    }
                }
            }
            if(fl) dp[i] = (dp[i]+dp[i-len2])%Mod;
        }
        printf("Case #%d: %lld
",cc++,dp[len1]);
    }
    return 0;
}
#include<iostream>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
string a,b;
long long dp[100010];
int mod=1e9+7;
int main()  
{  
    //freopen("in.txt","r",stdin);  
    //freopen("out.txt","w",stdout);  
    int t;  
    cin>>t;
    for(int Case=1;Case<=t;Case++)  
    {  
        memset(dp,-1,sizeof(dp));
        cin>>a>>b;
        dp[0]=1;
        for(int i=1;i<=a.length();i++){

            dp[i]=dp[i-1];
            if(i>=b.length()&&a.substr(i-b.length(),b.length())==b)
                dp[i]=(dp[i-b.length()]+dp[i])%mod;

        }
        printf("Case #%d: %d
",Case,dp[a.length()]);
        
    }  
    return 0;  
}  

1010

  • 官方题解

0可以转化成任意整数,包括负数,显然求LIS时尽量把0都放进去必定是正确的。因此我们可以把0拿出来,对剩下的做O(nlogn)的LIS,统计结果的时候再算上0的数量。为了保证严格递增,我们可以将每个权值S[i]减去i前面0的个数,再做LIS,就能保证结果是严格递增的。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100008;
int stk[N];
int a[N];
bool vis[N];
int Bsearch(int l, int r, int val)
{
    int mid;
    while(l<=r){
        mid = (l+r)>>1;
        if(stk[mid]==val) return mid;
        else if(stk[mid]<val) l = mid+1;
        else r = mid-1;
    }
    return l;
}
int main()
{
    int T;
    scanf("%d",&T);
    int cc = 1;
    while(T--)
    {
        memset(vis,0,sizeof(vis));
        int n;
        scanf("%d",&n);
        int sum = 0;
        for(int i = 1; i <= n; i++){
            scanf("%d",&a[i]);
            if(a[i]==0){
                sum++;
                vis[i] = 1;
            }
            else a[i] -= sum;
        }
        int cnt = 1;
        //memset(stk,-1,sizeof(stk));
        stk[0] = -111111111;
        for(int i = 1; i <= n; i++){
            if(vis[i]==1) continue;
            if(a[i]>stk[cnt-1]) stk[cnt++] = a[i];
            else {
                int id = Bsearch(1,cnt-1,a[i]);
                stk[id] = a[i];
            }
        }
        printf("Case #%d: %d
",cc++,cnt+sum-1);
    }
    return 0;
}

1011

  • 直接人肉
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#include<map>
using namespace std;
map <string,int> m;

int main()
{
    int T;
    m["Cleveland Cavaliers"] = 1;
    m["Golden State Warriors"] = 2;
    m["San Antonio Spurs"] = 5;
    m["Miami Heat"] = 3;
    m["Dallas Mavericks"] = 1;
    m["L.A. Lakers"] = 11;
    m["Boston Celtics"] = 17;
    m["Chicago Bulls"] = 6;
    m["Houston Rockets"] = 2;
    m["Detroit Pistons"] = 3;
    m["Philadelphia 76ers"] = 2;
    m["Seattle Sonics"] = 1;
    m["Washington Bullets"] = 1;
    m["Portland Trail Blazers"] = 1;
    m["New York Knicks"] = 2;
    m["Milwaukee Bucks"] = 1;
    m["St. Louis Hawks"] = 1;
    m["Minneapolis Lakers"] = 5;
    m["Philadelphia Warriors"] = 2;
    m["Syracuse Nats"] = 1;
    m["Rochester Royals"] = 1;
    m["Baltimore Bullets"] = 1;
    //scanf("%d",&T);
    cin>>T;
    string s;
    char c[55];
    getchar();
    int cnt = 0;
    while(T--)
    {
        cnt++;
        //getchar();
        //cin.getline(s);
        gets(c);
        s = c;
       //printf("%s",c);
       //cout<<c;
        int ans = m[c];
        printf("Case #%d: %d
",cnt,ans);
    }
    return 0;
}

1012

  • 题意:

读题真的很重要,我不是很想写题意,前面的也都没写,因为用自己的话说明题意是一个累累的事情,
这个题,就是让你求有在冒泡排序中每个元素最远到达的位置。
找个规律就好了,肯定要先和它后面的元素交换

* 官方题解

考虑一个位置上的数字c在冒泡排序过程的变化情况。c会被其后面比c小的数字各交换一次,之后c就会只向前移动。数组从右向左扫,树状数组维护一下得到每个值右边有多少个比其小的值,加上原位置得到最右位置,最左位置为初始位置和最终位置的最小值。 时间复杂度(O(n lg n))

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100008;
int ans[N];
int mp[N];
int tree[N];

int lb(int x){
    return x&(-x);
}
void add(int x,int n){
    while(x<=n){
        tree[x]++;
        x+=lb(x);
    }
}
int sum(int x){
    int ans = 0;
    while(x>0){
        ans+=tree[x];
        x-=lb(x);
    }
    return ans;
}
int b[N];
int main()
{
    int T;
    int n;
    int cnt = 0;
    scanf("%d",&T);
    while(T--)
    {
        cnt++;
        scanf("%d",&n);
        memset(tree,0,sizeof(tree));
        for(int i = 1; i <= n; i++){
            scanf("%d",&mp[i]);
        }
        ans[n] = 0;
        for(int i = n; i >= 1; i--){
            ans[i] = sum(mp[i]-1);
            add(mp[i],n);
        }
         for(int i = 1;i <= n;i++)
        {
            int x = ans[i];
            if(i >= mp[i])
            {
                b[mp[i]] =  i+x-mp[i];
            }
            else
            b[mp[i]] = max(mp[i] - i, x) ;
        }
        printf("Case #%d:",cnt);
        for(int i = 1;i <= n;i++)
            printf(" %d",b[i]);
        printf("
");

    }
    return 0;
}

多校5

1003

  • 官方题解

把长度为n的序列分成尽量多的连续段,使得每一段的每个前缀和都不小于0。保证有解。 从后往前贪心分段即可

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const ll N = 1000008;
ll a[N];
int main()
{
    ll n;
    while(~scanf("%lld",&n))
    {
        for(ll i = 0; i < n; i++){
            scanf("%lld",&a[i]);
        }
        ll ans = 0;
        ll sum = 0;
        for(ll i = n-1; i >=0; i--){
            if(a[i]<0){
                sum += a[i];
            }
            else if(a[i]>=0&&sum>=0){
                ans++;
            }
            else if(a[i]>=0&&sum<0){
                sum+=a[i];
                if(sum>=0){
                    sum = 0;
                    ans++;
                }
            }
        }
        printf("%lld
",ans);
    }
    return 0;
}

#include<cstdio>

const int N=1e6+7;
int a[N];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)scanf("%d",a+i);
        long long sum=0,ans=0;
        for(int i=n;i>=1;i--)
        {
            sum+=a[i];
            if(sum>=0)ans++,sum=0;
        }
        printf("%lld
",ans);
    }
    return 0;
}

1011

  • 官方题解

水题。dp[i][j]表示A序列前i个数和B序列前j个数的相同子序列对有多少个。复杂度(O(n^2))

  • 我的理解

(dp[i][j]) 表示A序列前i个数和B序列前j个数的相同子序列对有多少个,那么对于(dp[i][j])肯定包含了(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])的情况。如果最后一个字符是一样的话还可以考虑只有这一位的子序列相同。还要考虑到这一位和前面每一个相同的串组成的串都是相同的,即(dp[i][j] = 2*dp[i][j]+1)
注意一般有mod的时候要用((a%mod+mod)%mod) 来保证它是模Mod后最小的正整数

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const ll N = 1004;
ll dp[N][N];
ll a[N];
ll b[N];
const ll Mod = 1000000007;
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        memset(dp,0,sizeof(dp));
        for(int i = 1; i <= n; i++)
            scanf("%lld",&a[i]);
        for(int i = 1; i <= m; i++)
            scanf("%lld",&b[i]);
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                dp[i][j] = (dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%Mod;
                dp[i][j] = (dp[i][j]%Mod+Mod)%Mod;
                if(a[i]==b[j]){
                    dp[i][j] = (dp[i][j]+dp[i-1][j-1]+1)%Mod;
                }
            }
        }
        printf("%lld
",dp[n][m]);
    }
    return 0;
}

多校5题解

多校6

1001

  • 官方题解

[sum_{0leq k_{1},k_{2},cdots k_{m}leq n}prod_{1leq j< m}inom{k_{j+1}}{k_{j}} =sum_{0leq k_{1}leq k_{2}leqcdots leq k_{m}leq n}prod_{1leq j< m}inom{k_{j+1}}{k_{j}} =sum_{k_{m}=0}^{n}sum_{k_{m-1}=0}^{k_{m}}cdots sum_{k_{1}=0}^{k_{2}}prod_{1leq j< m}inom{k_{j+1}}{k_{j}}=sum_{k_{m}=0}^{n}left { inom{k_{m}}{k_{m-1}} sum_{k_{m-1}=0}^{k_{m}} left { inom{k_{m-1}}{k_{m-2}} cdots sum_{k_{1}=0}^{k_{2}}inom{k_{2}}{k_{1}} ight } ight } =sum_{k_{m}=0}^{n}left { inom{k_{m}}{k_{m-1}} sum_{k_{m-1}=0}^{k_{m}} left { inom{k_{m-1}}{k_{m-2}} cdots sum_{k_{1}=0}^{k_{2}}inom{k_{2}}{k_{1}} ight } ight } =sum_{k_{m}=0}^{n}left { inom{k_{m}}{k_{m-1}} sum_{k_{m-1}=0}^{k_{m}} left { inom{k_{m-1}}{k_{m-2}} cdots sum_{k_{2}=0}^{k_{3}}inom{k_{3}}{k_{2}}2^{k_{2}} ight } ight } =sum_{k_{m}=0}^{n}m^{k_{m}} =frac{m^{n+1} - 1}{m - 1} ]

  • 我的做法

不知道小伙伴上面的推理看懂了吗。反着我是没有,所以我就采取了找规律的暴力方法,还是找出了后面的那个公式,然后就是用数学的方法,费马小定理也可以,扩展欧几里得也可以,反正是通过求逆元的方法来解决了这个公式,上面的用一个快速幂就可以了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const ll Mod = 1000000007;
ll qmul(ll a, ll k)
{
    ll ans = 1;
    while(k > 0){
        if(k%2==1){
            ans *= a;
            ans%=Mod;
        }
            a*=a;
            a%=Mod;
        k >>= 1;
    }
    return ans;
}
ll gcd(ll x, ll y, ll &a, ll &b){
    if(y==0){
        a = 1;
        b = 0;
        return x;
    }
    ll tm = gcd(y,x%y,a,b);
    int tt = a;
    a = b;
    b = tt - x/y*b;
    //printf("%lld
",tm);
    return tm;
}
ll niyuan(ll n){
    ll a, b;
    ll aa = gcd(n,Mod,a,b);
    /*while(a<0) {
        a+=Mod;
        a%=Mod;
    }*/
    a = (a%Mod+Mod)%Mod;
    return a;
}
int main()
{
    int T;
    scanf("%d",&T);
    ll n,m;
    while(T--)
    {
        scanf("%lld %lld",&n,&m);
        ll tm = (qmul(m,n+1)-1)%Mod;
        //printf("%lld
",tm);
       //ll a,b;
       //printf("    %lld  %lld   %lld
",gcd(2,Mod,a,b),a,b);
        tm*=niyuan(m-1);
        tm%=Mod;
        tm = (tm%Mod+Mod)%Mod;
        printf("%lld
",tm);
    }
    return 0;
}
  • 来自小绿豆的经验传授
    用 %= 、 +=等运算符,要比用 y = y+a 要快很多

nim

  • 题解

找sg函数的规律就可以了,打个表实在不行就打个表,总是可以发现规律的

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        int ans = 0;
        int tm;
        int sg;
        for(int i= 0; i < n ;i++){
            scanf("%d",&tm);
            if(tm%8==7) sg = tm+1;
            else if(tm%8==0) sg = tm-1;
            else sg = tm;
            ans = ans^sg;
        }
        if(ans==0) puts("Second player wins.");
        else puts("First player wins.");
    }
    return 0;
}

多校7

1001

  • tj

(E[V] = E[frac{sum_{i=1}^{m} (X_i - ar X)^2}{m}]=E[(X_i - ar X)^2] = E[X_i^2 - 2X_iar X +ar X^2]) (= E[X_i^2] - 2ar XE[X_i] + E[ar X^2] = E[X_i^2] - 2ar X^2 + ar X^2 = E[X_i^2] - frac{n^2}{m^2}) 所以关键是要求出(E[X_i^2]). 我们用随机变量(Y_j)来表示第j个球是否在第i个盒子中,如果在则(Y_j = 1),否则(Y_j = 0). 于是 (E[X_i^2] = E[(sum_{j=1}^{n} Y_j)^2] = E[sum_{j=1}^{n} Y_j^2] + 2E[sum_{j=1}^{n} sum_{k=1,k eq j}^{n} Y_jY_k] = nE[Y_j^2] + n(n-1)E[Y_jY_k]) (=frac{n}{m}+frac{n(n-1)}{m^2}) 因此, (E[V] = frac{n}{m} + frac{n(n-1)}{m^2} - frac{n^2}{m^2} = frac{n(m-1)}{m^2})

  • 我又是找的规律
#include <iostream>
#include <stdio.h>
using namespace std;
long long int gcd(long long int a,long long int b){
   return b==0?a:gcd(b,a%b);

}
int main()
{
    long long int n,m;
    while(scanf("%lld%lld",&n,&m)&&(n!=0||m!=0)){
        long long int fenzi;
        long long int fenmu;
        if(m==1){
            fenzi = 0;
            fenmu = m;
        }
        else{
            fenzi = (m-1)*n;
            fenmu = m*m;
            //cout<<fenzi<<" "<<fenmu<<endl;
            if(gcd(fenmu,fenzi)>1){
                long long int temp = gcd(fenmu,fenzi);
                fenzi = fenzi/temp;
                fenmu = fenmu/temp;
            }
        }
        printf("%lld/%lld
",fenzi,fenmu);
    }
    return 0;
}

1005

  • 题解

将顶点按能到达的点数从小到大排序,排好序之后每个点只能往前面的点连边. 因而如果存在一个排在第i位的点,要求到达的点数大于i-1,则不可行;否则就可以按照上述方法构造出图. 复杂度O(N^2).

吐槽:用数组就超时了,用vector就过了。。。我也是醉了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1008;
struct Node{
    int val;
    int id;
    bool operator < (const Node a) const
    {
        return val < a.val;
    }
}a[N];
//int l[N],r[N];
vector <int> l;
vector <int> r;
int main()
{
    int T;
    scanf("%d",&T);
    int cnt = 1;
    while(T--)
    {
        l.clear();
        r.clear();
        int n;
        scanf("%d",&n);
        for(int i = 0; i < n; i++){
            scanf("%d",&a[i].val);
            a[i].id = i;
        }
        sort(a,a+n);
        bool fl = 1;
        for(int i = 0; i < n; i++){
            if(a[i].val > i) {
                fl = 0;
                break;
            }
            else {
                for(int j = 0; j < a[i].val; j++){
                    //l[c] = a[i].id+1;
                    //r[c++] = a[j].id+1;
                    l.push_back(a[i].id+1);
                    r.push_back(a[j].id+1);
                }
            }
        }
        printf("Case #%d: ",cnt++);
        if(fl==0) puts("No");
        else if(fl){
            puts("Yes");
            int c = l.size();
            printf("%d
",c);
            for(int i = 0; i < c; i++){
                printf("%d %d
",l[i],r[i]);
            }
        }
    }
    return 0;
}

1010

  • tj

比较简单巧妙的一个做法是引入一个新的栈C,每次合并的时候就把A和B合并到C上,然后把A和B都清空. push还是按正常做,pop注意当遇到要pop的栈为空时,因为题目保证不会对空栈进行pop操作,所以这时应直接改为对C栈进行pop操作. 这样做因为保证每个元素最多只在一次合并中被处理到,pop和push操作当然也是每个元素只做一次,所以总复杂度是O(N)的. 另一种做法是用链表来直接模拟,复杂度也是O(N),但代码量稍大一些.

  • 我一开始wa在了,我采用了假出栈的方法,最后发现,这样会导致,有些不合法的未合并的数也被加入了这个栈
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100008;
struct Node {
    int val;
    int id;
}A[N],B[N],C[N];
int a, b, c;
int main()
{
    int n;
    char ml[10];
    char ch;
    int tm;
    int cc = 1;
    int cnt;
    while(~scanf("%d",&n),n)
    {
        cnt = 0;
        printf("Case #%d:
",cc++);
        a = b = c = 0;
        for(int i = 0; i < n; i++){
            scanf("%s",ml);
            getchar();
            if(ml[1]=='u'){
                scanf("%c %d",&ch,&tm);
                if(ch=='A'){
                    A[a].val = tm;
                    A[a++].id = cnt++;
                }
                if(ch=='B'){
                    B[b].val = tm;
                    B[b++].id = cnt++;
                }
            }
            else if(ml[1]=='e'){
                scanf("%c %c",&ch,&ch);
                int i, j;
                for(i = 0, j = 0; i < a||j < b;){
                    if(i < a && j < b){
                        if(A[i].id<B[j].id){
                            C[c++].val = A[i].val;
                            i++;
                        }
                        else {
                            C[c++].val = B[j].val;
                            j++;
                        }
                    }
                    else if(i < a){
                        while(i < a){
                            C[c++].val = A[i++].val;
                        }
                    }
                    else if(j < b){
                        while(j < b){
                            C[c++].val = B[j++].val;
                        }
                    }
                }
                a = b = 0;
            }
            else if(ml[1] =='o') {
                scanf("%c",&ch);
                if(ch=='A'){
                    if(a>0){
                        printf("%d
",A[--a].val);
                    }
                    else {
                        printf("%d
",C[--c].val);
                    }
                }
                if(ch=='B'){
                    if(b>0){
                        printf("%d
",B[--b].val);
                    }
                    else {
                        printf("%d
",C[--c].val);
                    }
                }
            }
        }
    }
    return 0;
}

1001

  • tj

假设有4个红球,初始时从左到右标为1,2,3,4。那么肯定存在一种方案,使得最后结束时红球的顺序没有改变,也是1,2,3,4。 那么就可以把同色球都写成若干个不同色球了。所以现在共有n个颜色互异的球。按照最终情况标上1,2,。。,n的序号,那么贪心的来每次操作就是把一个区间排序就行了。

  • 我是想每个球最后都有一个要去的地方,那么每次对于一个处理的区间都尽可能的将这些球向自己要去的地方排序,然后如果可以的话,到最后一个区间取完的话每个球都应该在自己所在的地方
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1008;
int b[N];
struct Node{
    int val;
    int id;
   /* bool operator < (const Node a) const
    {
        return a.id>id;
    }*/
}a[N];
bool operator < (Node a, Node b)
{
    return a.id<b.id;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 0; i < n; i++){
            scanf("%d",&a[i].val);
            a[i].id = -1;
        }
        for(int i = 0; i < n; i++){
            scanf("%d",&b[i]);
            for(int j = 0; j < n; j++){
                if(a[j].val==b[i]&&a[j].id==-1){
                    a[j].id = i;
                    break;
                }
            }
        }
        for(int i = 0; i < m; i++){
            int l,r;
            scanf("%d%d",&l,&r);
            sort(a+l-1,a+r);
        }
        bool fl = 1;
        for(int i = 0; i < n; i++){
            if(a[i].val!=b[i]) {
                fl = 0;
                break;
            }
        }
        if(fl)puts("Yes");
        else puts("No");
    }
    return 0;
}

1006

tj

简单的物理题,发现球的碰撞只是交换了速度,因此可以看成没发生碰撞。这样解一个微分方程就可以算出每个球经过t秒之后的速度,如果球的初速度为v, 那么t秒后,球的速度为(sqrt(v ^ 2 + 2tC).) 只需要最开始对每个球的速度排序好就行了。

  • 由于是变加速度运动,肯定要用积分来解决.
    微元法:考虑一段极小的时间间隔:dt. 速度增量为 dv . 则:$dv = frac{C}{v}*dt $
    化简为 (vdv = Cdt)
    两边同时积分:dv的积分区间为[v0, v], dt的积分区间为[0, t].
    那么结果为:(v^2 = v_0^2+2Ct)
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 100008;
double v[N];
int main()
{
    int T;
    int x,d;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        double c;
        scanf("%d %lf",&n,&c);
        for(int i = 0; i < n; i++){
            scanf("%lf%d%d",&v[i],&x,&d);
        }
        sort(v,v+n);
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int t,k;
            scanf("%d%d",&t,&k);
            printf("%.3lf
",sqrt(2.0*c*t+v[k-1]*v[k-1]));
        }
    }
    return 0;
}

1010

  • tj

最优情况下一定交换第一个右括号和最后一个左括号,交换后判断一下即可。 时间复杂度 (O(n))

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100008;
char mp[N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        scanf("%s",mp);
        if(n%2==1){
            puts("No");
            continue;
        }
        int l, r;
        for(int i = 0; i < n; i++){
            if(mp[i]==')'){ r = i;
            break;
            }
        }
        for(int i = n-1; i >= 0; i--){
            if(mp[i]=='('){
                l = i;
                break;
            }
        }

        int L;
        L = 0;
        bool fl = 1;
        mp[r] = '(';
        mp[l] = ')';
       // printf("%s
",mp);
        for(int i = 0; i < n; i++){
            if(mp[i]=='('){
                L++;
            }
            else if(mp[i]==')'){
                if(L>0) L--;
                else {
                    fl = 0;
                    break;
                }
            }
        }
        if(fl){
            puts("Yes");
        }
        else puts("No");
    }
    return 0;
}

网络赛

1001

题解: 大数的模运算,可以直接一位一位的处理就可以了

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 10000008;
char mp[N];
const int Mod = 10001;
int main()
{
    int cc = 1;
    while(~scanf("%s",mp))
    {
        printf("Case #%d: ",cc++);
        int len = strlen(mp);
        int ans = 0;
        for(int i = 0; i < len; i++)
        {
           ans*=10;
           ans+=mp[i]-'0';
           ans%=Mod;
        }
        if(ans ==0 )
        printf("YES
");
        else puts("NO");
    }
    return 0;
}

hdu_5835

题解:
和之前刷的一个数学题一样,只要保证最大数目的糖果可以用隔板隔开的话,那么所有的糖一定可以通过排成单链的形式都放进去,然后一定所有的糖可以排成双链,那么如果不能的情况就要考虑有多少糖要浪费掉,那么考虑这些糖,可放入最多数目的那种糖果可以放入多少块,然后看最后不能放入的糖可以通过与其他排好的糖组成双链的情况放入,如果不可以的话,那么最后的结果就是隔板数,如果可以都放入就和第一种情况一样了,所有的糖都可以放入

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100004;
#define ll long long
ll a[N];
int main()
{
    int T;
    scanf("%d",&T);
    int cc = 1;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        ll sum = 0;
        ll mam = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%lld",&a[i]);
            sum+=a[i];
            mam = max(mam,a[i]);
        }
        ll ans;
        ll l;
        if((mam)>(sum-mam+1)){
            l = 2*(sum-mam)+1;
            if((2*mam-sum-1)>l){
                ans = l;
            }
            else ans = sum/2;
        }
        else ans = sum/2;
        printf("Case #%d: %lld
",cc++,ans);
    }
    return 0;
}

多校10

1002

简单的两园交面积,直接套用模板就可以了

1011

水题找规律就可以了

hdu_5861
因为一个路只能打开和关闭一次,所以只要用扫描一遍的方法统计出所有的路段最早开始的时间和最晚结束的时间就好了
1001
只要找规律就好了

5862
线段树,动态更新每个点的位置下面有几个线段

多校10 有很多有意思的题,但是由于本宝宝开学了,所以博客就写到这里吧。,。。这算是什么懒得打代码的接口。。。

原文地址:https://www.cnblogs.com/shanyr/p/5787954.html