日常TC计划正式启动!

Easy(250pts):

题目大意:给你一个集合,里面一堆数,初始数为0,给你一个目标数,你可以选择集合中若干个数进行OR操作来得到目标数。问至少删去多少个数,使得你永远无法达成目标,保证集合最多50个数,每个数<=10^9,且集合中的数两两互不相同。

显然我们要按照每个数的二进制位来考虑,由于所有的数<=10^9,所以最多只有30个二进制位。

如果集合中的一个数,存在某一位使得这个数为1,但是目标数为0,那么这个数一定不能取。

(因为如果取了,那么当前的数这一位就变成了1,然而不存在从1变成0的操作,所以永远无法成为目标数)

对于剩下的数,如果不能达到目标数,那么一定是存在一个二进制位使得目标数为1,其它数都是0。

那么显然只要扫一下就可以了。

时间复杂度O(n*logw),代码如下:

 #include <bits/stdc++.h>
using namespace std;
class ORSolitaire
{
public:
int getMinimum(vector <int> numbers,int t)
{
int ans=;
int n=numbers.size();
bool flag[];
for (int i=;i<n;i++)
{
flag[i]=true;
for (int j=;j<=;j++)
if ((numbers[i]&(<<j))&&((t&(<<j))==)) flag[i]=false;
}
for (int i=;i<=;i++)
{
int cnt=;
for (int j=;j<n;j++)
if ((numbers[j]&(<<i))&&flag[j]) ++cnt;
if (t&(<<i)) ans=min(ans,cnt);
}
return ans;
}
};

Medium(600pts):

题目大意:给你一个n*m的01矩阵,你需要尽可能少地改变矩阵中的数(0变成1,1变成0)使得矩阵中至少有r行是回文串,c列是回文串,输出最少操作次数。其中2<=n,m<=14,数据保证n和m都是偶数。

这应该是这场最烦的题目了吧,如果你会玄学优化,说不定可以搜过去~~~(大雾)

我们枚举2^m种的情况,每一列有回文或者不回文的情况,接下来我们考虑使用dp。

考虑dp的状态,如果只是一列一列的进行状态的转移,那么这样显然是不太好做的,因为你不知道这一行是否回文。

于是我们考虑首尾两行,两行两行进行转移。

我们可以先预处理出cost数组,cost[i][j]表示第i行和第n-1-i行一共有j个串是回文串的最小代价。(所以j=0,1,2)

这里我们显然可以通过枚举出2*2的小矩阵,对于2*2我们只要手判就可以了。

接下来考虑转移dp数组,f[i][j]表示前i行和后i行一共有j个串是回文串的最小代价。

于是我们有f[i][j]=min(f[i][j],f[i-1][j-k]+cost[i][k]),中间一些细节(特别是下标)考虑清楚就好了。

时间复杂度O(2^n*n^2),代码如下:

 #include <bits/stdc++.h>
#define inf 20000007
using namespace std;
int con[][],a[][];
int n,m;
class PalindromeMatrix
{
int countbit(int s)
{
int st=s,ans=;
while (st>)
{
ans+=(st%==);
st/=;
}
return ans;
}
int deal(int p0,int p1,int q0,int q1)
{
if (p0) p0=;
if (p1) p1=;
if (q0) q0=;
if (q1) q1=;
//p means whether two blocks in the row are the same
//q means whether two blocks in the column are the same
//the aim of the function is just to calculate the possible answer of the blocks of size 2*2
int cnt=;
for (int i=;i<=;i++)
for (int j=;j<=;j++)
cnt+=(con[i][j]==);
if (p0+p1+q0+q1>=) return min(cnt,-cnt);
//all the four blocks must be the same if the sum of p&q are not less than 3
else if(p0+p1+q0+q1==)
{
//there must be exact three blocks that are the same or two blocks in the two rows/columns
//then there will be four conditions
if (p0&&p1) return ((con[][]!=con[][])+(con[][]!=con[][]));
if (q0&&q1) return ((con[][]!=con[][])+(con[][]!=con[][]));
int tot=;
if (p0&&q0) tot=cnt-(con[][]==);
if (p0&&q1) tot=cnt-(con[][]==);
if (p1&&q0) tot=cnt-(con[][]==);
if (p1&&q1) tot=cnt-(con[][]==);
return min(tot,-tot);
} else if (p0+p1+q0+q1==)
{
//there will also be four conditions
int tot=;
if (p0) tot+=(con[][]!=con[][]);
if (p1) tot+=(con[][]!=con[][]);
if (q0) tot+=(con[][]!=con[][]);
if (q1) tot+=(con[][]!=con[][]);
return tot;
}
//then the answer must be 0
else return ;
}
int calc(int rowcnt,int st)
{
int cost[][],f[][];
for (int i=;i<n/;i++)
{
for (int j=;j<=;j++) cost[i][j]=*m;
//x means whether two blocks in the same row are the same
//y means whether two blocks in the same column are the same
for (int x1=;x1<=;x1++)
for (int x2=;x2<=;x2++)
{
int now=;
for (int j=;j<m/;j++)
{
int y1=st&(<<j),y2=st&(<<(m-j-));
con[][]=a[i][j];
con[][]=a[i][m-j-];
con[][]=a[n-i-][j];
con[][]=a[n-i-][m-j-];
now+=deal(x1,x2,y1,y2);
}
cost[i][x1+x2]=min(cost[i][x1+x2],now);
}
}
for (int i=;i<=n/;i++)
for (int j=;j<=rowcnt;j++)
f[i][j]=inf;
f[][]=;
for (int i=;i<=n/;i++)
for (int j=;j<=rowcnt;j++)
for (int k=;k<=&&k<=j;k++)
f[i][j]=min(f[i][j],f[i-][j-k]+cost[n/-i][k]);
return f[n/][rowcnt];
}
public:
int minChange(vector<string> s,int rowcnt,int colcnt)
{
n=s.size(),m=s[].length();
for (int i=;i<n;i++)
for (int j=;j<m;j++)
a[i][j]=s[i][j]-'';
int ans=inf;
for (int st=;st<(<<m);st++)
if (countbit(st)==colcnt) ans=min(ans,calc(rowcnt,st));
return ans;
}
};

Hard(900pts):

题目大意:给你两个整数A,B,求直线y=ax+b将平面分成了多少个部分,(a=0,1...A-1,b=0,1,...B-1)其中1<=A,B<=1200。

这是个很棒棒的公式题。

我们考虑把所有的直线一条一条加进来,那么我们只需要统计出每加进来一条直线会多出多少个平面就可以了。

对于直线y=ax+b,显然它不会和y=ax+c,其中c不等于b的直线相交。

于是我们只需要考虑直线y=ax+b和y=cx+d其中c<a且d<B的直线相交。

我们还需要注意到一个细节就是,如果有三条直线交在了同一个点上,那么对于答案的贡献度会减少1,

换句话说,我们要考虑的本质不是有多少直线相交,而是它们会相交出多少个交点。

考虑直线y=ax+b和y=cx+d,它们的交点P,那么Xp=(d-b)/(a-c),

我们将Xp视为p/q,那么我们只需要考虑本质不同的p/q有多少就可以了,

我们来观察一下p和q的范围,

其中p=d-b,那么p在-b~B-b的范围内,而q=a-c,于是q在1~a的范围内。

那么本质不同的p/q是什么呢,也就是p/q的数值不同,那么只需要考虑p和q互质的情况就可以了。

这里可以用莫比乌斯反演呢,但是A,B<=1200,所以直接暴力就好了。

所以这一题我们先预处理出1~i,1~j中有多少对数互质,接下来直接统计答案就可以了。

时间复杂度O(A^2),代码如下:

 #include <bits/stdc++.h>
using namespace std;
long long f[][];
class LotsOfLines
{
int gcd(int a,int b)
{
if (b==) return a;
return (gcd(b,a%b));
}
public:
long long countDivisions(int a,int b)
{
memset(f,,sizeof(f));
for (int i=;i<=a;i++)
for (int j=;j<=b;j++)
f[i][j]=f[i-][j]+f[i][j-]-f[i-][j-]+(gcd(i,j)==);
long long ans=+b;
for (int i=;i<a;i++)
for (int j=;j<b;j++)
ans=ans++f[i][j]+f[i][b-j-];
return ans;
}
};

完结撒花~

最新文章

  1. CE STEPLDR
  2. struts2基础——最简单的一个例子
  3. 写过的一些Oracle相关的博客
  4. Round Numbers(组合数学)
  5. 客户端通过spice-gtk实现USB重定向
  6. linux kernel的函数与抽象层
  7. C++学习笔记13-类继承
  8. Python学习之---冒泡,选择,插入排序
  9. 将数组写入Plist文件中
  10. 【XSY3309】Dreamweaver 高斯消元 拉格朗日插值
  11. vs变量监视提示-VAR-CREATE: UNABLE TO CREATE VARIABLE OBJECT解决方法
  12. PODOFO编译
  13. 访问前台页面${pageContext.request.contextPath}/el表达式失效问题解决
  14. 回首C语言关键字(~回首向来萧瑟处~)
  15. I/O流+统计文件词频
  16. web服务器压测工具siege、ab
  17. 稳定匹配 - Stable Matching
  18. spring读取classpath目录下的配置文件通过表达式去注入属性值.txt
  19. weex 开发 (已放弃了)
  20. Windows API 学习记录1

热门文章

  1. python基础之模块part2
  2. python基础之入门基础
  3. Git-Git分支
  4. Android开发——View滑动冲突解决方案
  5. qq登录面板
  6. 新工具填补Docker管理空白
  7. Spring mvc+hibernate+freemarker(实战)
  8. 站在C#和JS的角度细谈函数式编程与闭包
  9. 用Fragment实现如新浪微博一样的底部菜单的切换
  10. Pascal “内存病毒”(骗人的)