codeforces#341

A题:偶数直接加进去,奇数排序后去掉最小的即可。

/*
ID: NotPassedCET4
PROG: #341
LANG: C++
*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll o[maxn],on,e[maxn],en;
int n;

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n){
        on=en=0;
        REP(i,1,n){
            ll x;scanf("%I64d",&x);
            if(x&1) o[++on]=x;
            else e[++en]=x;
        }
        ll s=0;
        sort(o+1,o+on+1);
        REP(i,1,en) s+=e[i];
        int k=1;
        if(on&1) k=2;
        for(int i=on;i>=k;i--) s+=o[i];
        cout<<s<<endl;
    }
    return 0;
}

B题:由于主对角线和辅对角线对结果的影响是独立,所以分开找即可,对每个对角线内的k个棋子,对答案的贡献是C(k,2)。

/*
ID: NotPassedCET4
PROG: #341
LANG: C++
*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;
struct Node
{
    int x,y;
    int z,w;
};Node p[maxn];

bool cmpz(Node A,Node B)
{
    return A.z<B.z;
}

bool cmpw(Node A,Node B)
{
    return A.w<B.w;
}

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n){
        REP(i,1,n) scanf("%d%d",&p[i].x,&p[i].y);
        REP(i,1,n){
            p[i].z=p[i].x+p[i].y-1;
            p[i].w=p[i].x-p[i].y;
        }
        sort(p+1,p+n+1,cmpz);
        ll ans=0;
        for(int i=1;i<=n;){
            int j=i;
            while(j<=n&&p[j].z==p[i].z) j++;
            ll cnt=j-i;
            ans+=cnt*(cnt-1)/2;
            i=j;
        }
        sort(p+1,p+n+1,cmpw);
        for(int i=1;i<=n;){
            int j=i;
            while(j<=n&&p[j].w==p[i].w) j++;
            ll cnt=j-i;
            ans+=cnt*(cnt-1)/2;
            i=j;
        }
        cout<<ans<<endl;
    }
    return 0;
}

C题:对每个个体单独计算对答案的贡献期望即可,算是数学题吧。。写的时候碰到两个问题,一是算边界的时候用了二分,其实直接前缀和f(r)-f(l-1)即可,其中f(x)=x/p;另外一个是式子没写清楚,分母写错了。。

/*
ID: NotPassedCET4
PROG: #341
LANG: C++
*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n;ll pt;
struct Node
{
    ll l,r;
    ll len;
    ll x,y;
    void read()
    {
        scanf("%I64d%I64d",&l,&r);
        len=r-l+1;
        x=r/pt-(l-1)/pt;
        y=len-x;
    }
};Node p[maxn];

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n>>pt){
        REP(i,1,n){
            p[i].read();
        }
        double ans=0;
        REP(i,1,n){
            int j=i-1,k=i+1;
            if(j==0) j=n;
            if(k==n+1) k=1;
            double tmp=0;
            tmp+=(1.0*p[j].len*p[i].x*p[k].len+1.0*p[j].x*p[i].y*p[k].x)*2000;
            tmp+=(1.0*p[j].y*p[i].y*p[k].x+1.0*p[j].x*p[i].y*p[k].y)*1000;
            tmp/=1.0*p[j].len*p[i].len*p[k].len;
            ans+=tmp;
        }
        printf("%.8f\n",ans);
    }
    return 0;
}

E题:很容易写出dp方程,前i位余数为j的方案数为 dp[i][j]=dp[i-1][k]*cnt[t],其中j=(k*10+t)%x,i范围最大可到1e9,因此只有快速幂了。

先解出t=(j-10*k)%x;

那么为了方便快速幂,方程简化一下:f[i]=f[j]*cnt[(i-10*j)%x]。(0<=i<x)

f[i]为当前项,f[j]为前一项,显然转移矩阵为A[i][j]=cnt[(i-10*j)%x],这样问题就解决了。

大概如下。。。

| f[0] |              | A[0][0]  A[0][1]....         A[0][x-1]   |         | f[0] |

| f[1] |         =   |                                                     |        | f[1] |

| .   |               |                                                 |      *     |   .  |

|   .   |              |                                                   |          |    .  |

| f[x-1] |           |A[x-1][0] ............        A[x-1][x-1] |           | f[x-1]  |

/*
ID: NotPassedCET4
PROG: #341
LANG: C++
*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;
const ll p=1e9+7;

const int N=102;
ll n,b,k,x;
struct Matrix
{
    ll a[N][N];
    friend Matrix operator*(Matrix A,Matrix B)
    {
        Matrix res={};
        REP(i,0,x-1){
            REP(j,0,x-1){
                REP(k,0,x-1){
                    res.a[i][j]=(res.a[i][j]+((A.a[i][k]%p)*(B.a[k][j]%p))%p)%p;
                }
            }
        }
        return res;
    }
};
ll cnt[N];
ll Fs[N],Ft[N];

Matrix qpow(Matrix n,ll k)
{
    Matrix res={};
    REP(i,0,x-1) res.a[i][i]=1;
    while(k){
        if(k&1) res=res*n;
        n=n*n;
        k>>=1;
    }
    return res;
}

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n>>b>>k>>x){
        MS0(cnt);
        REP(i,1,n){
            int y;scanf("%d",&y);
            cnt[y%x]++;
        }
        REP(i,0,x-1) Fs[i]=cnt[i],Ft[i]=0;
        Matrix A;
        REP(i,0,x-1){
            REP(j,0,x-1){
                A.a[i][j]=cnt[(i+10*x-10*j)%x];
            }
        }
        A=qpow(A,b-1);
        REP(i,0,x-1){
            REP(j,0,x-1){
                Ft[i]=(((Fs[j]%p)*(A.a[i][j]%p))%p+Ft[i]%p)%p;
            }
        }
        cout<<Ft[k]<<endl;
    }
    return 0;
}

总结,代码速度和准确性并不算太差,但是用在分析的时间较少,对题目没有充分的分析和判断就直接写了,这导致比赛中常常选择不合理的思路。不过已经慢慢找回状态了。

时间: 2024-08-26 22:56:32

codeforces#341的相关文章

Codeforces Round #341 (Div. 2) ABCDE

http://www.cnblogs.com/wenruo/p/5176375.html A. Wet Shark and Odd and Even 题意:输入n个数,选择其中任意个数,使和最大且为奇数. 题解:算出所有数的和,如果奇数的个数为奇数个,则减去最小的奇数,否则不用处理. #include <bits/stdc++.h> using namespace std; #define PI acos(-1.0) #define EXP exp(1.0) #define ESP 1E-6

Codeforces Round #341 (Div. 2)

在家都变的懒惰了,好久没写题解了,补补CF 模拟 A - Wet Shark and Odd and Even #include <bits/stdc++.h> typedef long long ll; const int N = 1e5 + 5; const int INF = 0x3f3f3f3f; int main(void) { std::vector<int> vec; int n; scanf ("%d", &n); ll sum = 0;

Codeforces Round #341 Div.2 C. Wet Shark and Flowers

题意: 不概括了..太长了.. 额第一次做这种问题 算是概率dp吗? 保存前缀项中第一个和最后一个的概率 然后每添加新的一项 就解除前缀和第一项和最后一项的关系 并添加新的一项和保存的两项的关系 这里关系指的是两者相邻会产生的额外收入(其中一个满足条件就能得到 因此公式是 2000 * (rate[a] * rate[b] + rate[a] * ( 1 - rate[b]) + rate[b] * (1 - rate[a])) 至于一开始为什么老是调不过去呢..我发现添加第三项的时候前两项是不

Codeforces Round #341 Div.2 B. Wet Shark and Bishops

题意:处在同一对角线上的主教(是这么翻译没错吧= =)会相互攻击 求互相攻击对数 由于有正负对角线 因此用两个数组分别保存每个主教写的 x-y 和 x+y 然后每个数组中扫描重复数字k ans加上kC2就行了 wa了两发的原因是没考虑到如果整个数组都是重复的 那要最后额外加一次 #include <cstdio> #include <cmath> #include <cstring> #include <queue> #include <vector&

Codeforces Round #341 Div.2 A. Wet Shark and Odd and Even

题意是得到最大的偶数和 解决办法很简单 排个序 取和 如果是奇数就减去最小的奇数 #include <cstdio> #include <cmath> #include <cstring> #include <queue> #include <vector> #include <algorithm> #define INF 0x3f3f3f3f #define mem(str,x) memset(str,(x),sizeof(str)

Codeforces Round #341 (Div. 2) E. Wet Shark and Blocks(矩阵优化DP)

题目链接:点击打开链接 题意:给n个数作为一个块,有b个块,从其中若干个中选择数,每个块只能选一个数,最后组成一个数模x等于k的方法数. 思路:很容易想到这样一个DP方程 : 用dp[i][j]表示现在i位,余数是j.那么dp[i + 1][(j * 10 + k) % x] = dp[i][j] * cnt[k],k是指枚举放1~9中哪一位. 因为b特别大,显然要矩阵优化,知道了DP方程,其实矩阵的构造特别简单. 根据矩阵相乘的规则, 其实这个矩阵就是A[j][(j*10+a[k])%x]++

Codeforces Round #341 (Div. 2) C. Wet Shark and Flowers(简单容斥)

题目链接:点击打开链接 题意:有n个人围坐成一圈,每个人可以从a[i].l 到 a[i].r里选一个数,如果相邻两个数的乘积能整除p,那么就奖励他们一人1000,求所得钱的总和的期望. 思路:既然求期望, 先求概率. 显然是要求每组相邻两个人的值乘积能否被p整除, 可以很容易知道在区间里有多少个数不能被p整除, 正难则反, 就能算出相邻两个有多少种组合不能被p整除, 那么也就很容易算出每组可以被p整除的概率, 乘上2000就是每组的期望, 期望加和就是总的期望. 细节参见代码: #include

Codeforces Round #341 (Div. 2) E - Wet Shark and Blocks

题目大意:有m (m<=1e9) 个相同的块,每个块里边有n个数,每个数的范围是1-9,从每个块里边取出来一个数组成一个数,让你求组成的方案中 被x取模后,值为k的方案数.(1<=k<x<=100) 思路:刚开始把m看成了1e5,写了一发数位dp,果断RE,然后我在考虑从当块前状态转移到下一个块状态模数的改变都用的是一套规则,因为 每个块里面的数字都是一样的,那么我们就可以很开心地构造出一个x*x的矩阵进行快速幂啦. #include<bits/stdc++.h> #d

Codeforces Round #279 (Div. 2) ABCD

Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name     A Team Olympiad standard input/output 1 s, 256 MB  x2377 B Queue standard input/output 2 s, 256 MB  x1250 C Hacking Cypher standard input/output 1 s, 256 MB  x740 D Chocolate standard input/