Codeforces Round #659 (Div. 2)补题A,B1,B2,C,D

A

题意:
输出n+1个字符串,si和si+1的公共前缀长为ai
思路:
我们只要模拟过程即可,只要两个字母就可以输出任意多个满足题意的字符串。
我们只要改,第一个不相同的就好,后面的都输出一样的,但是一定要确保长度能够达到和下一个字符串相等的长度
思路好想,但是写的过程错了很多小细节,暴露代码能力
AC代码:

#include
using namespace std;
#define mod 1e9+7
#define N 100
#define inf 0x3f3f3f3f
const double PI = atan(1.0)*4.0;
typedef long long ll;
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
   // freopen("E:\\in.txt","r",stdin);
    int k;
    cin>>k;
    while(k--)
    {  char a[105][105];int b[105];
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>b[i];
            b[n+1]=50;
            for(int i=1;i<=b[1]+1;i++)
                a[1][i]='b';
        for(int i=2;i<=n+1;i++)
        {      int j;
            for( j=1;j<=b[i-1];j++)
            {
                a[i][j]=a[i-1][j];
            }
            if(a[i-1][j]=='a')a[i][j]='b';
            else a[i][j]='a';
            for(j++;j<=max(b[i]+1,b[i-1]+1);j++)
            {
                a[i][j]='a';
            }
        }
        for(int i=1;i<=n+1;i++)
        {
            for(int j=1;j<=max(b[i]+1,b[i-1]+1);j++)
                cout<<a[i][j];
            cout<<endl;
        }
 
    }
}

B1

题意:
有 n 片海域,每片海域有一个初始深度,每 2 * k秒,前 k秒 每秒深度 +1 ,后 k 秒每秒深度 -1 .有一个人想从海岸一边游到另一边 ,每秒它可以移动到下一片海域或者停留在当前海域,如果当前海域深度大于 l 他会被淹死,问他可不可以游到对岸。
思路:
这道题可以通过dp来做。
状态表示:f[i][j] //当这个人到达第i片海域的时间为j秒这个状态是否合法
状态计算:f[i][j]可以由两个状态转移得到
f[i][j-1] //上一秒在第i片海域选择不移动
f[i-1][j-1] //上一秒在第i-1片海域选择向右移动
只要两者有一个状态是合法的,那么f[i][j]就是可到达的。
然后我们还要证明f[i][j]状态本身是否合法,即在第j秒时海域i的深度是否大于l。
最后我们只需要找找f[n][j]的状态中是否有合法的即可,如果f[n][j]状态中有合法的,那么最终的结果就是Yes.

#include
#define LL long long
#define PII pair
using namespace std;
const int N=1e2+5,M=2e4+5;
int a[N],p[2*N];
int f[N][M];
void init(int k)
{
	for(int i=0;i<=k;i++) p[i]=i;		//预处理出涨潮的情况
	for(int i=1;i<k;i++) p[k+i]=k-i;
	
	for(int i=0;i<2*k;i++) f[0][i]=1;	//设置起点,进去的时间区间在[0,2k]内即可
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		memset(f,0,sizeof f);
		int n,k,l;
		cin>>n>>k>>l;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		
		init(k);
		for(int i=1;i<=n;i++)			//枚举海域
		for(int j=0;j<2*k*n;j++)		//枚举时间
		{
			f[i][j]=max(f[i][j-1],f[i-1][j-1]);		//计算状态f[i][j]是否可到达
			if(l<p[j%(2*k)]+a[i]) f[i][j]=0;		//计算f[i][j]本身是否合法
		}
		bool ok=false;
		for(int i=0;i<2*k*n;i++)
			if(f[n][i]) ok=true;
		
		if(ok) puts("Yes");
		else puts("No");
	}
	return 0;
}

B2

#include
using namespace std;
const int N=3e5+5;
int a[N];
void solve()
{
    int n,k,l,i;
    scanf("%d%d%d",&n,&k,&l);
    a[0]=a[n+1]=k+1;
    for(i=1; i<=n; i++)
        scanf("%d",&a[i]),
              a[i]=l-a[i];//a数组存放上涨a[i]后依然能通过
    int w=k+1,f=-1;//w表示当前潮汐高度f表示下一秒潮汐变化的数字
    for(i=1; i<=n; i++)
    {
        if(a[i]<0)
        {
            printf("No\n");    //无法通过
            return;
        }
        else if(a[i]>=k)
            w=k+1,f=-1;//若潮汐在最高处时这个点还是安全的,可以在这个点等到潮最高时
        else if(f==-1)
            w=min(w+f,a[i]);//只要当前是潮落的状态就可以等待
        else
        {
            w+=f;    //若是涨潮状态这个点已经不安全了则说明这个点无法通过
            if(w>a[i])
            {
                printf("No\n");
                return;
            }
        }
        if(w==0)
            f=1;
    }
    printf("Yes\n");
}

int main()
{
    freopen("E:\\in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}

C

题意:
在相对应的位置,只要 a 串上的字母大于 b 串上的字母,那么无解,否则一定有解。
要找到最小的步数,其实最大步数也就20吧。
我们首先从小的开始选择字母,对于选定的字母,我们可以把它变成什么呢?选择的字母都有其要变成的值,我们让他们都变成要变成字母里的最小的一个,比如:aaa–>cdg,那么选择的字母是 ′a′,把它变成 ′c′,然后把其都变成 ′c′。
具体实现使用 set 来维护的,每个字母维护一个 set,从小到大枚举,然后每次取当前字母要变换到的最小字母,操作次数++,然后将这些字母变成最小字母,其对应的操作就是把其余的放入到最小字母的那个set里。
复杂度 O(n∗log20)

#include
using namespace std;
const int man = 2e5+10;
#define ll long long
const ll mod = 1e9+7;
char s1[man],s2[man];

int main() {      
    
    int t;cin >> t;
    while(t--){
        int n;cin >> n;
        scanf("%s%s",s1+1,s2+1);
        bool f = 1;
        for(int i = 1;i <= n;++i){
            if(s1[i]>s2[i]){
                f = 0;
                break;
            }
        }
        if(!f){
            cout <<"-1\n";
            continue;
        }
        int ans = 0;
        set<int>s[25];
        for(int i = 1;i <= n;++i){
            if(s1[i]!=s2[i]){//只把不同的放入
                s[s1[i]-'a'].insert(s2[i]-'a');
            }
        }
        for(int i = 0;i < 20;++i){
            if(s[i].size()==0)continue;
            int minn = *s[i].begin();
            s[i].erase(minn);
            ans++;
            for(auto it:s[i]){
                s[minn].insert(it);
            }
        }
        printf("%d\n",ans);
    }   
    return 0;
}

D博弈游戏

题意:
有 n 个数,Koa 和另一个人比赛,每个数只能拿一次,两个人手上的值都是 0 ,使得每拿一个数都与自己手上的数进行异或,自己手上的数变成当前异或值,最后谁手上的书最大谁获胜
从决定位也就是最高位入手,由高位往低位分析。
我们设当前位为1的数字个数为x,0为y。
如果x为偶数,则无论怎么选,最后两个得分在这个位都是一样的
如果x为奇数,且x % 4 == 1,则先手的得分在该位一定是1,后手一定为0;如果x % 4 == 3, 且 y % 2 == 0,则后手完全可以跟随先手的操作,最后先手在该位一定是偶数个1,异或结果为0,先手输。如果x%4 == 3,且y % 2 == 1,那么先手一定能赢,因为先手可以一上来拿该位为0的数,使得整个局势转移到上一中情形。

#include 
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int maxn = 2e6;
const int inf = 0x3f3f3f3f;
int bit[40];
int main()
{
    int t; cin >> t;
    while(t--)
    {
        int n; cin >> n;
        memset(bit, 0,sizeof(bit));
        for(int i = 1; i <= n; i++)
        {
            ll z; cin >> z;
            for(int j = 0; j <= 32; j++)
                if(z & (1ll << j))
                    bit[j]++;
        }
        int flag = 0;
        for(int i = 32; i >= 0; i--)
            if(bit[i] & 1)
            {
                int x = bit[i], y = n - bit[i];
                if(x % 4 == 1) flag = 1;
                else
                {
                    if(y % 2 == 0) flag = -1;
                    else flag = 1;
                }
                break;
            }
        if(flag == 1) cout << "WIN" << endl;
        else if(flag == -1) cout << "LOSE" << endl;
        else cout << "DRAW" << endl;

    }
}

你可能感兴趣的:(div2)