【LCC α Round1】Final Match

【LCC α Round1】Final Match

A 音乐大师 atcoder4299

题目描述

lxd家里有N个开关和M盏电灯, 开关的编号从1到N, 分别是 s 1 , s 2 , s 3 . . . . . . . . s_1,s_2,s_3........ s1,s2,s3........。开关状态只有两种:“打开”和“关闭”。当这些开关中“打开”的开关数量模2后与 p i p_i pi相同, 这盏灯将会亮起。
作为一个音乐大师, lxd不仅希望自己的音乐有着坚实的节奏, 还要有华丽的视觉效果, 于是他想用开关的编排将这些灯全部打开。请问共有多少种“打开”“关闭”的组合可以点亮所有的灯?

题目思路

用二进制, 0, 表示开关关上, 1代表打开。因为数据很小, N只有10, 所以共有2n种情况,这些情况转化成二进制就是0到 2 n − 1 2^n-1 2n1, 所以我们直接可以枚举这些情况, 并用vis数组记录下当前这种情况下哪些灯是亮着的, 然后遍历每个灯泡, 统计他们的开着的灯泡和模2是否与对应的a数组相等, (其实这步可以转化成异或, 因为是模2, 答案只有1和2)还有, 只有当全部灯泡都符合情况时, 这种情况才算上。

代码

#include
using namespace std;
int n,m,a[15];
bool vis[15];
vector<int>v[15];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        while(x--)
        {
            int y;
            scanf("%d",&y);
            v[i].push_back(y);
        }
    }
    for(int i=1;i<=m;i++)
        scanf("%d",&a[i]);
    int ans=0;
    for(int i=0;i<1<<n;i++)
    {
        memset(vis,false,sizeof(vis));
        for(int j=0;j<n;j++)
            if(1<<j&i) vis[j+1]=true;
        bool flag=true;
        for(int j=1;j<=m;j++)
        {
            int res=0;
            for(int k=0;k<v[j].size();k++)
                if(vis[v[j][k]]) res^=1;
            if(res!=a[j]) flag=false;
        }
        ans+=flag;
    }
    printf("%d\n",ans);
}

B ljm的游戏 Codeforces1167B

题目描述

本题是一道交互题
首先ljm拿出了六张牌, 上面分别写着4,8,15,16,23,42这六个整数, 之后ljm把这六张牌打乱了。。。。。
现在你最多可以对ljm的新牌堆进行四次询问, 每次询问可以得知排队自下而上的第i张牌和第j张牌,的乘积是多少。你能根据这些信息猜出这六张牌的顺序吗?
请注意, 实际评测时,交互其不是自适应的, 交互器将不会跟据你的询问内容而调整牌堆的实际顺序。

交互题(代码简介+交互方式(此题))

在最终提交你的答案前, 你最多可以提出4个询问。询问的方式是输出这样一行信息:

scanf("? %d %d\n", i, j);

其中i, j是你自己设的变量, 均满足KaTeX parse error: Undefined control sequence: \lep at position 3: 1 \̲l̲e̲p̲ ̲i,j \leq 6的整数, 这行信息应一个换行符结束。
在发出这个信息后, 你需要使用下面这行代码来刷新的IO缓存, 保证交互器能收到你的信息。

fflush(stdout);

当交互器接收到你发出的信息后, 它会返回牌堆自上而下的第i张牌和第j张牌的乘积,这是你要采用正常的方式来读入交互器给你的信息

cin >> i;

最终输出及答案时, 你的程序应该输出这样一行信息:

! a1 a2 a3 a4 a5 a6;

题目思路

人生第一道交互题啊~~
我们从小到大来分析:
假如只有1个数, 不用问;
2个同理, 实际上无法确定;
三个数由于保证两两相乘唯一, 所以问1和2, 还有1 和 3.
忽然发现, 6 = 3 * 2!!!
所以, 我们可以把6张牌化成两组, 1,2,3一组, 4,5,6一组。
这样只需要询问1,2;1,3;4,5;4,6就好了。
其实本来想写很多个if, 后来想, 可以用next——permutation啊!!!

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
 
 using namespace std;
 
 int x[] = {4, 8, 15, 16, 23, 42};
 int main()
 {
 	int ab;
 	printf("? 1 2\n");
 	fflush(stdout);
 	cin >> ab;
 	int ac;
 	printf("? 1 3\n");
 	fflush(stdout);
 	cin >> ac;
 	int de;
 	printf("? 4 5\n");
 	fflush(stdout);
 	cin >> de;
 	int df;
	 printf("? 4 6\n");
	 fflush(stdout);
	 cin >> df;
	 do{
	 	if(x[0] * x[1] == ab && x[0] * x[2] == ac&& x[3] * x[4] == de && x[3] * x[5] == df)
	 	{
	 		printf("! %d %d %d %d %d %d\n", x[0], x[1], x[2], x[3], x[4], x[5]);
	 		break;
	 	}
	 	}while(next_permutation(x, x+6)); 
 	return 0;
 }

C 炸油条的lxn poj1239

题目描述

我们的红太阳lxn要和面炸油条, 她现在已经把面擀成了一个长长的面团。我们将面团用一个只含有数字的字符串来表示, 现在你需要lxn把这个字符串用‘,’分割开来, 使整个字符变成一个严格递增的序列, 并努力使最后一个数字尽可能地小。
输出的字符串可能含有前导0, 输出时请一并输出

题目思路

严格递增, 最大的数尽可能地小, 对了, 可以用dp吗, 线性往前推:
正反两次dp;
先去求最大的数可能的最小值, 再去求第一个数最大能是多少。
假如读入的字符串是str的话。。。
dp[i] = j表示str[1…i]序列生成的递增序列里最后一个数的最小值是str[j…i]
dp2[i] = j表示str[i…end]序列生成的递增序列里, 第一个数最大是str[i…j]
总的来说, 两种转移方式如下。

向后规划

那么i就从前往后, 对于每个i, j从i-1的地方开始, 也就是从最大数最小这个地方开始规划, 如果不合法, j就-1,把最小数变大, 那么直到j合法的那一刻, str[j…i]就是合法的最大数最小j。

向前规划

i从后往前, j从前往后, 思想和上面一致。

如何判断

第一种只要最后一个数的前一个数比他小即可。
如下图:
【LCC α Round1】Final Match_第1张图片
将他俩比较即可。
第二种是第一个数比它后面的小即可:
【LCC α Round1】Final Match_第2张图片
万事俱备, 只欠比较
代码里见吧

代码

include<cstdio>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
 
 using namespace std; 

char str[110],s[110];

int dp[110],dp2[110];

int cmp(int b1,int e1,int b2,int e2)

{

	while(str[b1]=='0')

		b1++;

	while(str[b2]=='0')

		b2++;

	int len1=e1-b1+1;

	int len2=e2-b2+1;

	if(len1<len2)

		return -1;

	else

		if(len1>len2)

			return 1;

		else

			return strncmp(str+b1,str+b2,len1);

}

int main()

{

	while(scanf("%s",str)!=EOF)

	{

		if(strcmp(str,"0")==0)

			break;

		memset(dp,0,sizeof(dp));

		memset(dp2,0,sizeof(dp2));

		int len=strlen(str);

		int i,j;

		for(i=1;i<len;i++)

		{

			for(j=i-1;j>=0;j--)

			{

				if(cmp(dp[j],j,j+1,i)<0)

				{

					dp[i]=j+1;

					break;

				}

			}

		}

		i=dp[len-1];

		dp2[i]=len-1;

		while(str[i-1]=='0')

		{

			dp2[i-1]=len-1;

			--i;

		}

		for(i=dp[len-1]-1;i>=0;i--)

		{

			for(j=i;j<dp[len-1];j++)

			{

				if(cmp(i,j,j+1,dp2[j+1])<0&& dp2[i]<j)

				{

					dp2[i]=j;

				}

			}

		}

		i=0;

		while(i<len)

		{

			strncpy(s,str+i,dp2[i]-i+1);

			s[dp2[i]-i+1]='\0';

			if(i!=0)

				printf(",");

			printf("%s",s);

			i=dp2[i]+1;

		}

		printf("\n");

	}

}

D lxn粉丝群的复读姬 HDU-4080

题目描述

hzw仔细地研究了复读姬复读的消息, 发现复读姬复读的一条消息里面会有大量的重复信息, 而且复读姬有几率模糊复读, 比如一条消息babbab,复读姬可能会复读成babab因为中间有两个b
所以现在复读机复读的消息可能含有大量重叠的重复消息。hzw因为还要AK World Final, 所以他把这个分析复读机消息的重任交给了你。
给定一个整数m和表示复读机复读消息的字符串s, 你需要找到s中出现至少m次的最长子串。如果有多个, sh输出位置最靠右的那个。
保证出现次数不超过11次。
如果没有输出none。

题目思路

由于样例略了, 一大家最好还是先去看看原题, 字符串匹配问题用hash,
最大长度,次数多, 用二分。完美。
二分字符串长度, 如果出现次数大于m,往右边找。。。。
后缀数组是什么, 能吃吗。

代码

#include

#define ull unsigned long long

using namespace std;

const int maxn = (int)4e4 + 10;

int n,len;

char s[maxn];

ull has[maxn];

ull p = 2333,a[maxn];

 

bool judge(int x)

{

	map<int,int> mp;

	ull res;

	for (int i = 1;i + x - 1 <= len;i ++)

	{

		res = has[i + x - 1] - has[i - 1] * a[x];

		if (++mp[res] >= n) return 1;

	}

	return 0;

}

int check(int x)

{

	map<int,int> mp;

	int pos = -1;

	ull res;

	for (int i = 1;i + x - 1 <= len;i ++)

	{

		res = has[i + x - 1] - has[i - 1] * a[x];

		if (++mp[res] >= n) pos = i;

	}

	return pos - 1;

}

int main()

{

	while (~scanf("%d",&n) && n)

	{

		scanf("%s",s + 1);

		len = strlen(s + 1);

		has[0] = 0,a[0] = 1;

		for (int i = 1;i <= len;i ++)

		{

			has[i] = has[i - 1] * p + s[i];

			a[i] = a[i - 1] * p;

		}

		int l = 1,r = len + 1,mid;

		while (l <= r)

		{

			mid = (l + r) >> 1;

			if (judge(mid)) l = mid + 1;

			else r = mid - 1;

		}

		if (r == 0)

			printf("none\n");

		else

			printf("%d %d\n",r,check(r));

	}

	return 0;	

}

E-云旅游 CodeForces 1276B

题目描述

AK大陆有n个城市, 其中一些城市之间通过双向道路。摆正陈大爷可以从任何一个城市抵达任何其他的城市。城市自1到n编号。
在这些城市中, 有两个不同的城市正在举办这一年一度的AK大赛, 这两个城市分别是城市a和城市b。
请帮沉的也找出所有的如果要从城市x到城市y, 必须要途径城市a和城市b的城市对, (x,y)和(y,x)是做同一个城市对。

题目思路

其实就是找必须通过a点到b和经过b点到a的城市个数在相乘。
怎么找呢,必须通过a才能到b,实际上我们对b点跑bfs,然后并且限制不能经过a点,那么看有多少个不能到达的点即可。后者一样。

代码

#include
#define int long long
using namespace std;
const int N=2e5+10;
int T,n,m,a,b,res,vis[N],cnt;
vector<int> v[N];
inline void add(int a,int b){v[a].push_back(b); v[b].push_back(a);}
inline int bfs(int x,int y){
    queue<int> q;   q.push(x);  cnt=2;  memset(vis,0,8*(n+1)); vis[x]=vis[y]=1;
    while(q.size()){
        int u=q.front();    q.pop();
        for(int i=0,to;i<v[u].size();i++){
            to=v[u][i];
            if(!vis[to])    vis[to]=1,q.push(to),cnt++;
        }
    }
    return n-cnt;
}
signed main()
{
    cin>>T;
    while(T--){
        cin>>n>>m>>a>>b;
        for(int i=1,x,y;i<=m;i++)   cin>>x>>y,add(x,y);
        res=bfs(a,b); 	res*=bfs(b,a);
        cout<<res<<'\n';
        for(int i=1;i<=n;i++)   v[i].clear();
    }
    return 0;
}

这个代码不对。。。。
哈哈

小结。

那天忘打了, 今天补上。

你可能感兴趣的:(比赛)