Codeforces Round #553 div.2

题目链接:戳我

好久没有写CF了(实际上好久没有动脑子了),实在是惨淡至极。这几天打算每天都开virtual contest qwq......

A

注意情况的分类讨论qwq

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 100
using namespace std;
int n,ans=0x3f3f3f3f;
char s[MAXN];
inline int dis(char from,char to)
{
    int cur_ans=0x3f3f3f3f;
    if(to>from) 
    {
        cur_ans=min(cur_ans,to-from);
        cur_ans=min(cur_ans,from-'A'+'Z'-to+1);
    }
    else 
    {
        cur_ans=min(cur_ans,from-to);
        cur_ans=min(cur_ans,'Z'-from+to-'A'+1);
    }
    return cur_ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++) cin>>s[i];
    for(int i=1;i+3<=n;i++) 
    {
        int cur_ans=0;
        cur_ans+=dis(s[i],'A');
        cur_ans+=dis(s[i+1],'C');
        cur_ans+=dis(s[i+2],'T');
        cur_ans+=dis(s[i+3],'G');
        ans=min(ans,cur_ans);
    }
    printf("%d\n",ans);
    return 0;
}

B

正解好像是DP......但是异或等于0的概率其实很小,而且还有special judge QAQ完全可以用随机化算法对吧!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<ctime>
#define MAXN 2048
using namespace std;
int n,m,cnt;
int a[MAXN][MAXN];
struct Node{int x,y;};
vector<Node>vec;
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    srand(time(0));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int cur=rand()%m+1;
        vec.push_back((Node){i,cur});
        ans^=a[i][cur];
    }
    while(ans==0&&cnt<=10000000)
    {
        int cur=rand()%vec.size();
        ans^=a[vec[cur].x][vec[cur].y];
        vec[cur].y=rand()%m+1;
        ans^=a[vec[cur].x][vec[cur].y];
        cnt++;
    }
    if(ans==0) printf("NIE\n");
    else 
    {
        printf("TAK\n");
        for(int i=0;i<vec.size();i++)
            printf("%d ",vec[i].y);
    }
    // cout<<(double)clock()/CLOCKS_PER_SEC<<endl;
    return 0;
}

C

两个long long相乘之前一定要记得取模
区间问题不好处理,但是从1开始就比较容易的问题可以用差分解决
1,3,5,7这种奇数序列的前缀和为\(i^2\),2,4,6,8这种偶数序列的前缀和为\(i^2+i\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define mod 1000000007
using namespace std;
ll l,r;
inline ll sum(ll x)
{
    ll last=0,cnt1=0,cnt2=0,ans=0;
    for(ll i=1,j=1;last<x;i<<=1,j++)
    {
        // printf("i=%lld last=%lld\n",i,last);
        if(j&1)
        {
            if(last+i<=x) cnt1+=i,last+=i;
            else cnt1+=(x-last),last=x;
        }
        else
        {
            if(last+i<=x) cnt2+=i,last+=i;
            else cnt2+=(x-last),last=x;
        }
        // printf("cnt1=%lld cnt2=%lld\n",cnt1,cnt2);
    }
    // cout<<cnt1<<" "<<cnt2<<endl;
    cnt1%=mod,cnt2%=mod;
    ans=(ans+cnt1*cnt1%mod)%mod;
    ans=(ans+cnt2*cnt2%mod)%mod;
    ans=(ans+cnt2%mod)%mod;
    return ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    cin>>l>>r;
    cout<<((sum(r)-sum(l-1))%mod+mod)%mod<<endl;
    return 0;
}

D

把式子展开一下就行了,是一个定值+\(\sum a[i]-b[i]\)
然后贪心一下就行了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAXN 100010
using namespace std;
int n;
struct Node{int a,b,sum,id;}node[MAXN];
inline bool cmp(struct Node x,struct Node y)
{
    return x.sum>y.sum;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&node[i].a,&node[i].b);
        node[i].sum=node[i].a-node[i].b;
        node[i].id=i;
    }
    sort(&node[1],&node[n+1],cmp);
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=1ll*node[i].b*n-node[i].a;
        ans+=1ll*i*node[i].sum;
    }
    cout<<ans<<endl;
    return 0;
} 

E

这个题都说简单可是我还是没有做出来。。。。
题意:每次保留值为[l,r]区间的点,问\(\sum_{l=1}\sum_{r=l+1}\)的联通块的个数。
因为是一条链,所以我们可以考虑每个点的贡献。
对于每个点,假设它是连通块里面编号最大的QAQ,那么就一定有编号i+1不在该联通块里。
如果a[i]>a[i+1],贡献为\(a[i]-a[i+1]*(n-a[i]+1)\)
如果a[i]<=a[i+1],贡献为\((a[i+1]-a[i])*a[i]\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 100010
using namespace std;
int n;
long long ans;
long long a[MAXN];
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d",&n);
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<n;i++)
	{
		if(a[i]<=a[i+1]) ans+=1ll*(a[i+1]-a[i])*a[i];
		else ans+=1ll*(a[i]-a[i+1])*(n-a[i]+1);
	}
	cout<<ans+1ll*(n-a[n]+1)*a[n]<<endl;
	return 0;
}

F

题目大意:给你一个长度为N的数列,里面只有0或者1。可以操作K次,每次交换两个数。询问K次之后的数列中,为不下降序列的概率为多少?
对1e9+7取模。
不下降序列只有一种,就是前(0的个数,这里设为m)位置为0,后面的为1。
一个神奇的DP(好吧也不神奇),就是设\(dp[i][j]\)表示第i次操作后,前m个位置中有j个1的方案数。

这样子我们就可以递推了。
前m个位置中有m-j个0,j个1;后面有j个0,n-m-j个1.
递推这个样子写:

for(int i=1;i<=k;i++)
	{
		for(int j=0;j<=min(m,n-m);j++)
		{
			if(j+1<=min(m,n-m)) 
				dp[i][j+1]=(dp[i][j+1]+1ll*dp[i-1][j]*(m-j)%mod*(n-m-j)%mod)%mod;
			//0<-->1
			dp[i][j]=(dp[i][j]+1ll*dp[i-1][j]*(m-j)%mod*j%mod)%mod;
			//0<-->0
			dp[i][j]=(dp[i][j]+1ll*dp[i-1][j]*j%mod*(n-m-j)%mod)%mod;
			//1<-->1
			dp[i][j]=(dp[i][j]+(1ll*dp[i-1][j]*(m-1)*m/2)%mod)%mod;
			//前m中交换
			dp[i][j]=(dp[i][j]+(1ll*dp[i-1][j]*(n-m-1)*(n-m)/2)%mod)%mod;
			//后n-m个中交换
			if(j-1>=0) 
				dp[i][j-1]=(dp[i][j-1]+1ll*dp[i-1][j]*j%mod*j%mod)%mod;
			//1<-->0
		}
	}

但是这个样子会T......
所以要加一个矩阵快速幂QAQ(注意计算后一定要返回值啊QAQ)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAXN 110
#define mod 1000000007
using namespace std;
int n,k,m,nn;
int a[MAXN],dp[MAXN][MAXN];
struct Node{int t[MAXN][MAXN];}init,ans;
inline int fpow(int x,int y)
{
	int cur_ans=1;
	while(y)
	{
		if(y&1) cur_ans=1ll*cur_ans*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return cur_ans;
}
inline Node calc(Node x,Node y)
{
	Node cur_ans;
	for(int i=0;i<=nn;i++)
		for(int j=0;j<=nn;j++)
			cur_ans.t[i][j]=0;
	for(int i=0;i<=nn;i++)
		for(int j=0;j<=nn;j++)
			for(int p=0;p<=nn;p++)
			{
				cur_ans.t[i][j]=(cur_ans.t[i][j]+1ll*x.t[i][p]*y.t[p][j]%mod)%mod;
				// printf("cur[%d][%d]=%d\n",i,j,cur_ans.t[i][j]);
			}
	return cur_ans;
}
inline Node solve(Node x,int y)
{
	Node cur_ans;
	for(int i=0;i<=nn;i++)
		for(int j=0;j<=nn;j++)
			cur_ans.t[i][j]=0;
	for(int i=0;i<=nn;i++) cur_ans.t[i][i]=1;
	while(y)
	{
		if(y&1) cur_ans=calc(cur_ans,x);
		x=calc(x,x);
		y>>=1;
	}
	return cur_ans;
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	cin>>n>>k;
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&a[i]);
		if(a[i]==0) m++; 
	}
	int cur=0;
	for(int i=1;i<=m;i++) if(a[i]==1) cur++;
	int c1=(1ll*(m-1)*m/2)%mod;
	int c2=(1ll*(n-m-1)*(n-m)/2)%mod;
	nn=min(n-m,m);
	for(int i=0;i<=nn;i++)
	{
		init.t[i][i]=(init.t[i][i]+(c1+c2)%mod)%mod;
		init.t[i][i]=(init.t[i][i]+(1ll*(m-i)*i)%mod)%mod;
		init.t[i][i]=(init.t[i][i]+(1ll*(n-m-i)*i%mod))%mod;
		if(i+1<=nn) 
			init.t[i][i+1]=(init.t[i][i+1]+1ll*(m-i)*(n-m-i)%mod)%mod;
		if(i-1>=0)
			init.t[i][i-1]=(init.t[i][i-1]+1ll*i*i%mod)%mod;
	}
	// for(int i=0;i<=nn;i++)
	// {
	// 	for(int j=0;j<=nn;j++)
	// 		cout<<init.t[i][j]<<" ";
	// 	cout<<endl;
	// }
	init=solve(init,k);
	ans.t[0][cur]=1;
	ans=calc(ans,init);
	int fn=1ll*fpow(fpow(n*(n-1)/2,k),mod-2)%mod;
	cout<<1ll*ans.t[0][0]*fn%mod<<endl;
	return 0;
}
posted @ 2019-04-25 10:20  风浔凌  阅读(113)  评论(0编辑  收藏  举报