Codeforces Round #313 (Div. 1) A B C

来源:互联网 发布:vb command透明 编辑:程序博客网 时间:2024/05/22 13:33

A Gerald's Hexagon

        水题,补成一个大三角形,然后减去缺的三个小三角形。

#include <bits/stdc++.h>      using namespace std;    #define ll long longconst int maxn=100010;int a[10];int tb[3010];int main(){int delta=1;for(int i=1;i<=3000;i++){tb[i]=tb[i-1]+delta;delta+=2;}for(int i=1;i<=6;i++){cin>>a[i];}int len=a[1]+a[2]+a[3];int ans=tb[len];ans-=tb[a[1]];ans-=tb[a[3]];ans-=tb[a[5]];cout<<ans<<endl;return 0;}

 

B Equivalent Strings

        判断两个串“等价”。等价的定义是,1.相等;2.当串长度为偶数时,把两个串分别分为左右两半,串a的左半部分和串b的右半部分等价,串a的右半部分和串b的左半部分等价。注意这是一个递归的定义。

        普通的dfs分治一下就可以过。有个效率更高的做法,就是对两个串分别单独处理,归并排序使得字典序最小,然后判两个串是否相等。

#include <bits/stdc++.h>      using namespace std;    #define ll long longconst int maxn=100010;char a[200010];char b[200010];bool dp[21][200010];int len;int h;static int cnt=0;bool dfs(int lv,int ida,int idb){cnt++;if(lv==h){int curlen=len>>lv;int posa=curlen*ida-curlen;int posb=curlen*idb-curlen;for(int i=0;i<curlen;i++){if(a[posa]!=b[posb])return 0;posa++;posb++;}return 1;}bool re=0;if(dfs(lv+1,ida*2-1,idb*2-1)&&dfs(lv+1,ida*2,idb*2) ){return 1;}if(dfs(lv+1,ida*2-1,idb*2)&&dfs(lv+1,ida*2,idb*2-1) ){return 1;}return 0;}int main(){scanf("%s%s",a,b);len=strlen(a);int tmp=len;h=0;while(tmp%2==0){h++;tmp>>=1;}bool ok = dfs(0,1,1);if(ok){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}return 0;}

C Gerald and Giant Chess

        一个h*w的网格,你需要从(1,1)走到(h,w),只能朝着h或w的方向走。另外,有n个坏的格子是不能走的,问有多少条路径。

        首先很容易想到的是,如果没有坏格子,从u(x1,y1)走到v(x2,y2)的路径数是C(x2-x1+y2-y1,x2-x1),记为calc(u,v)。然后这道题可以用dp来做,dp(s,i)表示从起点走到第i个坏点有多少种路径。如果可以这样走:s->u->v,那么dp(s,v)=calc(s,v)-dp(s,u)*calc(u,v),注意不是dp(s,v)=calc(s,v)-dp(s,u)*dp(u,v),我比赛时就一直认为是这样所以没做出来。另外组合数取模需要逆元,可以用费马小定理计算。通过这题,我学习到了费马小定理。

#include <bits/stdc++.h>      using namespace std;    #define ll long longconst int mod = 1e9+7;int h,w,n;ll Pow(ll a,int n){ll re=1;while(n){if(n&1){re*=a;re%=mod;}a*=a;a%=mod;n>>=1;}return re;}struct Point{int r,c;bool operator<(const Point& other)const{if(r==other.r)return c<other.c;return r<other.r;}}pt[2010];ll dp[2010];int inv[200010];//i的阶乘的逆元 ll fab[200010];    //组合数   ll C(int n,int k){      ll res=fab[n]*inv[k];      res%=mod;      res*=inv[n-k];      res%=mod;      return res;  }  int main(){fab[0]=1;      for(int i=1;i<=200000;i++){          fab[i]=fab[i-1]*i;          fab[i]%=mod;      }        inv[0]=1;//注意这个不能漏     for(int i=1;i<=200000;i++){//费马小定理计算阶乘的逆元 inv[i]=Pow(fab[i],mod-2);}cin>>h>>w>>n;for(int i=1;i<=n;i++){scanf("%d%d",&pt[i].r,&pt[i].c);}sort(pt+1,pt+n+1);//排序后,就可以递推dp,不用记忆化搜索 pt[0].r=pt[0].c=1;pt[n+1].r=h;pt[n+1].c=w;for(int v=1;v<=n+1;v++){dp[v]=C(pt[v].r-pt[0].r+pt[v].c-pt[0].c,pt[v].r-pt[0].r);for(int i=1;i<v;i++){if(pt[i].c<=pt[v].c){ll tmp=dp[i]*C(pt[v].r-pt[i].r+pt[v].c-pt[i].c,pt[v].r-pt[i].r);tmp%=mod;dp[v]-=tmp;dp[v]+=mod;dp[v]%=mod;}}}cout<<dp[n+1]<<endl;return 0;}

0 0
原创粉丝点击