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 2n−1, 所以我们直接可以枚举这些情况, 并用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);
}
本题是一道交互题
首先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;
}
我们的红太阳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从前往后, 思想和上面一致。
第一种只要最后一个数的前一个数比他小即可。
如下图:
将他俩比较即可。
第二种是第一个数比它后面的小即可:
万事俱备, 只欠比较
代码里见吧
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");
}
}
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;
}
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;
}
这个代码不对。。。。
哈哈
那天忘打了, 今天补上。