Croc Champ 2013 - Round 2 (Div. 2 Edition) 补题报告 A.B.(思维) C.(博弈论) D.(DFS+剪枝) E(待补)

目录

  • A - Ksusha and Array
  • B - Ksusha the Squirrel
  • C - Weird Game
  • D - Distinct Paths

A - Ksusha and Array

要找一个数能够整除数组内其他数,否则输出-1。很明显,要能整除其他数,这个数一定是最小的那一个。若最小的那个数能满足条件,则输出最小的,否则,输出-1。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#include 
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
 
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod 
	ll ans=1;
	while(n){
		if(n&1) ans=((ans%mod)*(a%mod))%mod;
		a=((a%mod)*(a%mod))%mod;
		n>>=1;
	}
	return ans%mod;
}
//==============================================================
const int maxn=1e5+10;
int n,a[maxn];


int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	//===========================================================
	read(n);rep(i,1,n) read(a[i]);
    sort(a+1,a+1+n);
    int ans=a[1],flag=0;
    rep(i,2,n){
        if(a[i]%ans){
            flag=1;
            break;
        }
    }
    if(flag){
        puts("-1");
    }
    else{
        write(ans);
    }
	//===========================================================
	return 0;
}

B - Ksusha the Squirrel

找有没有连续’#'的长度>=k就好了,有则过不去。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#include 
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
 
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod 
	ll ans=1;
	while(n){
		if(n&1) ans=((ans%mod)*(a%mod))%mod;
		a=((a%mod)*(a%mod))%mod;
		n>>=1;
	}
	return ans%mod;
}
//==============================================================
const int maxn=3e5+10;
char mp[maxn];
int n,k;


int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	//===========================================================
	read(n),read(k);scanf("%s",mp+1);
    int con=0,pre=0,flag=0;
    rep(i,1,n){
        if(mp[i]=='#'&&con==0){
            con=1;
            pre=i;
        }
        if(mp[i]=='.'&&con==1){
            con=0;
            if(i-pre>=k){
                flag=1;
                break;
            }
        }
    }
    if(flag||mp[n]=='#') puts("NO");
    else puts("YES");
	//===========================================================
	return 0;
}

C - Weird Game

这道题感觉好难。。
简单博弈论的一种思路就是求出这个局面能够操作几次,根据操作次数的奇偶性求出结果。
这道题我们把1分为三类:
a、b都能拿的,只有a能拿的,只有b能拿的。然后,我们有三种有效的操作:拿自己的1、拿自己的0堵对方的1,或者两者都有。
最优的策略应该是:首先先拿a、b都能拿的,这样做的收益最大:既能拿到自己的1,也能堵住对方的。
对于a、b都能拿的部分(cnt3),a能拿到cnt3/2+cnt3%2(因为先手),b能拿到cnt3/2
对于只有a、b各自能拿的部分(cnt1,cnt2),a、b都各自拿自己的。若一个人先拿完了,则会开始堵对方。但是,这个只有当a能取的比b的少的时候才可能逆转局势(a先手),所以,只有当cnt1==cnt2-1的时候,a拿走一个才能改变局势。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#include 
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
 
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod 
	ll ans=1;
	while(n){
		if(n&1) ans=((ans%mod)*(a%mod))%mod;
		a=((a%mod)*(a%mod))%mod;
		n>>=1;
	}
	return ans%mod;
}
//==============================================================
int n;
string s,t;
int res1,res2;


int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	//===========================================================
    cin>>n>>s>>t;
    int cnt1=0,cnt2=0,cnt3=0;
    rep(i,0,2*n-1){
        if(s[i]=='1'&&t[i]=='1') cnt3++;
        else if(s[i]=='1') cnt1++;
        else if(t[i]=='1') cnt2++;
    }
    cnt3%=2;
    cnt1+=cnt3;
    if(cnt1==cnt2-1) cnt2--;
    if(cnt1>cnt2) puts("First");
    else if(cnt1<cnt2) puts("Second");
    else puts("Draw");
	//===========================================================
	return 0;
}

D - Distinct Paths

参考博客:https://www.cnblogs.com/Harry-bh/p/8798883.html
这道题看着有点恐怖,但是,k<=10,因此,若从起点到终点的距离(n+m-1)>k,则一定没有方案,直接输出0就行了,这样,n+m<=10,可以搜索了。
然后要怎么搜索呢?对于颜色,我们可以状压:因为k<=10,1<<10=1024,不大,考虑二进制压缩。我们可以搜索整个图,枚举每个0点的颜色,验证可不可行。因为每个位置只能从上面或左面进入,因此,我们要求点可以选择的颜色,可以从左边和上边的状态得到。设f[i][j]表示到达i、j点的所有路径用过的颜色的二进制压缩,因此,有:f[i]][j]=f[i-1][j] or f[i][j-1]。
对于每个位置x,y:
若x,y本来就有颜色,则,验证当前颜色与f[i][j]中是否有重叠,若有,则该方案不成立,直接return。否则,继续搜索。
若x,y没有颜色,我们就枚举该点的颜色,继续搜索。
所能到达点(x+1,y)说明方案成立,return 1.
但是光这样还过不了,需要剪枝叶:
可行性剪枝:对于一点(x,y),若其到点(n,m)能用的颜色<该点到(n,m)的距离,则不需要搜下去。
对称性剪枝:若该点为0,我们选择了一种颜色i,得到方案数为tmp,则,下次再选一个颜色j,对应方案数也为tmp,所以就不用再搜索了,直接加到res中就行了。
但是注意:这里对颜色i、j有要求,就是i、j等这些颜色必须得是在这个图里没用过的,因为为了避免一种情况,如:
000
010
000
在(1,1)点,我们选颜色1和选颜色2,显然方案数是不一样的。所以,我们需要记录下这个颜色在这个图里是否被用过(记颜色i被用的次数为c[i])。
经过这两个剪枝之后就能顺利通过了。(注意回溯)
留意一个技巧:若j&(i)==0,j|=i之后,则可以通过j^=i还原。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#include 
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
 
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod 
	ll ans=1;
	while(n){
		if(n&1) ans=((ans%mod)*(a%mod))%mod;
		a=((a%mod)*(a%mod))%mod;
		n>>=1;
	}
	return ans%mod;
}
//==============================================================
const int maxn=1000+100;
int n,m,k;
int mp[maxn][maxn];
int f[maxn][maxn];
int c[maxn];
//ll re[maxn];
inline int cal(int x){
    //if(re[x]!=-1) return re[x];
    //ll&res=re[x];
    ll cnt=0;
    rep(i,1,k){
        if(!(x&(1<<i))) cnt++;
    }
    return cnt;
}
ll solve(int x,int y){
    if(x>n) return 1;
    int nxtx=x,nxty=y+1;
    if(nxty>m) nxty%=m,nxtx+=1;
    int flag=0;
    ll tmp=0;
    f[x][y]=(f[x-1][y]|f[x][y-1]);
    int num=cal(f[x][y]);
    if(num<n-x+m-y+1) return 0;
    ll res=0;
    if(mp[x][y]){
        if(!(f[x][y]&(1<<mp[x][y]))){
            f[x][y]|=(1<<mp[x][y]);
            res=(res+solve(nxtx,nxty))%mod;
            f[x][y]^=(1<<mp[x][y]);
        }
    }
    else{
        rep(i,1,k){
            if(!(f[x][y]&(1<<i))){
                if(c[i]==0){
                    if(flag){res+=tmp;res%=mod;}
                    else{
                        flag=1;
                        c[i]++;
                        f[x][y]|=(1<<i);
                        tmp=solve(nxtx,nxty);
                        f[x][y]^=(1<<i);
                        c[i]--;
                        res+=tmp;
                        res%=mod;
                    }
                }
                else{
                    c[i]++;
                    f[x][y]|=(1<<i);
                    res+=solve(nxtx,nxty);
                    f[x][y]^=(1<<i);
                    c[i]--;
                    res%=mod;
                }
            }
        }
    }
    return res;
}


int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
    clock_t c1 = clock();
	//===========================================================
	read(n),read(m),read(k);
    //memset(re,-1,sizeof(re));
    rep(i,1,n) rep(j,1,m) read(mp[i][j]),mp[i][j]?c[mp[i][j]]++:23333;
    if(n+m-1>k){
        puts("0");
        return 0;
    }
    ll ans=solve(1,1);
    write(ans);
	//===========================================================
    std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
	return 0;
}

你可能感兴趣的:(cf)