http://acm.hdu.edu.cn/showproblem.php?pid=5971
(这道题的题意有点说的不太明白,我大体理解是这样的:)
有n个玩家,m场比赛,其中有x个人是good,y个人是bad,每一场比赛都看做是一个good和一个bad的比赛,问是否所有人都能分成good和bad。
其实这题我一直有个疑问,就是关于“不确定”的情况,如果是一个正方形ABCD,那么按测试用例就是可以分的,但按我的理解,只能确定AC和BD分为两组,但谁是good谁是bad并不知道。不过既然测试用例是这样的,也经历了若干发wa,这题应该只能这么理解:
首先这个图有可能是断的,那么如果有1个点的分量,若它是不知道的,那就不能确定,否则,则看这个分量在部分点已经确定颜色的情况下能否二分染色即可
不过我还是吃了一大记wa,因为颜色数组不能当visited数组 有颜色的点不一定访问过,这样在搜的时候有可能会停下来。
#include
using namespace std;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
typedef long long ll;
int n,m,x,y;
int u,v;
vector<int> g[1005];
int c[1005];
int father[1005],num[1005],id[1005];
bool vis[1005];
bool dfs(int u,int col) { //给u点染col
c[u]=col;
vis[u]=true;
for(int i=0;iint v=g[u][i];
if(c[v]==col)
return false;
else if(!vis[v]) {
if(col==1) {
if(!dfs(v,2)) return false;
}
else {
if(!dfs(v,1)) return false;
}
}
}
return true;
}
int find(int x) {
return father[x]==x?x:find(father[x]);
}
void Union(int i,int j) {
i=find(i);
j=find(j);
if(i!=j) {
father[i]=j;
num[j]+=num[i];
}
}
int main() {
while(~scanf("%d %d %d %d",&n,&m,&x,&y)) {
for(int i=1;i<=n;i++) {
g[i].clear();
}
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
father[i]=i;
num[i]=1;/*开始时数量都为1,根节点为自己*/
id[i]=0;
}
for(int i=0;iscanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
Union(u,v);
}
for(int i=0;iscanf("%d",&u);
c[u]=1;
id[find(u)]=u;
}
for(int i=0;iscanf("%d",&u);
c[u]=2;
id[find(u)]=u;
}
bool ans=true;
if(n==1 && c[1]==0)
ans=false;
for(int i=1;i<=n;i++) {
if(num[find(i)]==1 && c[i]==0) {
ans=false;
break;
}
}
if(ans) {
for(int i=1;i<=n;i++) {
int p=find(i);//得到i点的祖先
if(id[p]==0) { //这一坨都没有染过色
ans=dfs(p,1);
}
else { //id[p]表示有染色的点
ans=dfs(id[p],c[id[p]]);
}
if(!ans)
break;
}
}
if(ans)
printf("YES\n");
else
printf("NO\n");
}
}
http://acm.hdu.edu.cn/showproblem.php?pid=5973
有两堆石头子,一堆n个一堆m个,两人做游戏,每次可以拿一堆的任意多个,或两堆同时拿相同多个,拿到最后一个的获胜,求同样采取最优策略下,先手胜还是后手胜?
这个叫威佐夫博弈,后手胜当且仅当
n=⌊(m−n)1+5√2⌋ .
用到大数还是写java吧。。。。这题可以拿去做模板.
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static BigDecimal gold = new BigDecimal("1.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475408807538689175212663386222353693179318006076672635443338908659593958290563832266131992829026788");
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
BigDecimal a = new BigDecimal(sc.next());
BigDecimal b = new BigDecimal(sc.next());
if(a.compareTo(b)==1) {
BigDecimal c=a;
a=b;
b=c;
}
BigDecimal temp = b.subtract(a).multiply(gold).subtract(a);
//if(a!=floor(k*gold)
if(temp.compareTo(BigDecimal.ONE)==-1 && temp.compareTo(BigDecimal.ZERO)==1)
System.out.println(0);
else
System.out.println(1);
}
}
}
http://acm.hdu.edu.cn/showproblem.php?pid=5974
求X和Y,满足 X+Y=a,lcm(x,y)=b .
表面上看挺简单的,a才20000,枚举a求lcm就得了,但那就完蛋了,因为测试用例有12万个。
遇到lcm还是要往gcd上去想。设 gcd(x,y)=c,x=ic,y=jc ,则原式化为:
#include
using namespace std;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
typedef long long ll;
ll gcd(ll a, ll b)
{
if(b==0)
return a;
return gcd(b,a%b);
}
ll a,b;
int T;
int main() {
while(~scanf("%I64d %I64d",&a,&b)) {
ll c=gcd(a,b);
ll dt=a*a-4*b*c;
if(dt<0) {
cout<<"No Solution"<continue;
}
else {
ll sq=sqrt(dt);
if(sq*sq!=dt) {
cout<<"No Solution"<continue;
}
else if((a+sq)%(2*c)){
cout<<"No Solution"<continue;
}
else {
ll x1=(a-sq)/2;
ll x2=(a+sq)/2;
cout<' '<
http://acm.hdu.edu.cn/showproblem.php?pid=5976
输入数字x,把x拆成若干不相同的数字,使得乘积最大。
Leetcode第343题的变形。原题题解我写过:http://blog.csdn.net/cmershen/article/details/51548825
原题的基础上加了不相同的要求,那么就不可能拆出尽可能多的3或2了,而只能是2,3,4,5…这么拆.
那么首先二分k,使得 2+..+k≤x<2+...+k+k+1 .那么就存在一个 s∈[0,k] ,使得 2+...+k+s=x .
接下来讨论s:
* s=0: 答案就是 k!
* s=k: 把2和s合并为k+2
* 其他: 把s和k+1-s合并为k+1
因为数据很大,先预处理出k!%M和k的乘法逆元。算了一下x的范围是 109 ,k最多取到44721.这个计算量和空间完全可以接受。(而且二分答案个人认为可以看做是O(1)复杂度的,因为答案范围终归是有限的,与输入的n无关)
#include
using namespace std;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
typedef long long ll;
const int M = 1e9+7;
ll a[44800],b[44800],c[44800];
int T;
ll n;
int egcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1;
y = 0;
return a;
}
int ans = egcd(b, a % b, x, y);
int temp = x;
x = y;
y = temp - a / b * y;
return ans;
}
int cal(int a, int m = M) { //扩展欧几里得算法模板,求a关于M的乘法逆元
int x, y;
int gcd = egcd(a, m, x, y);
if (1 % gcd != 0)
return -1;
x *= 1 / gcd;
m = abs(m);
int ans = x % m;
if (ans <= 0)
ans += m;
return ans;
}
void pre() {
b[0]=1;
for(int i=1;i<=44723;i++) {
a[i]=i*(i+1)/2-1;
b[i]=b[i-1]*i%M;
c[i]=cal(i);
}
}
int find(ll x) {
int l=1,r=44721;
while(l//cout<","<int mid=(l+r)/2;
if(a[mid]<=x && x1])
return mid;
else if(a[mid]>x)
r=mid;
else
l=mid+1;
}
return -1;
}
int main() {
pre();
scanf("%d",&T);
while (T--) {
scanf("%I64d",&n);
if(n<=4) {
printf("%lld\n",n);
continue;
}
int k=find(n);
int s=n-a[k];
ll ans=0;
if(s==0) {
ans=b[k];
}
else if(s==k) {
ans=b[k]*c[2]%M;
ans=ans*(k+2)%M;
}
else {
ans=b[k]*c[k+1-s]%M;
ans=ans*(k+1)%M;
}
printf("%lld\n", ans);
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=5978
一个暗箱里有1个红球和n个黑球,两人轮流不放回的取,谁先取到红球谁赢。问先手方和后手方谁优?或是公平?
先写递推公式:
如果n=0,则先手方必胜。 P0=1.
如果n=1,则是公平的。 P1=12.
…
对任意n,先手方第一步有 1/n 的机会一步获胜,如果不能获胜,还需要对方败,那么得出递推式:
Pn=1n+n−1n(1−Pn−1) .
写几项发现如果n为奇数则 Pn=1/2 ,否则 Pn>1/2 .如果是比赛,直接那么写过去就过了。
不过学习的过程是不允许一知半解的。
接下来我们用数学归纳法证明这个结论。
首先 P0=1>1/2,P1=1/2 .假设对 k∈N+ ,有 P2k>1/2,P2k+1=1/2 .
P2k+2=12k+2+2k+12k+2⋅12=2k+34k+4=12+14k+4>12.
P2k+3=12k+3+2k+22k+3⋅(1−2k+34k+4)=12.
#include
using namespace std;
typedef long long ll;
int k;
int main(){
while (~scanf("%d",&k)) {
if(k==1)
printf("0\n");
else
printf("1\n");
}
}
http://acm.hdu.edu.cn/showproblem.php?pid=5979
有个凸多边形,每个点距离原点的距离都是d,相邻两个点和原点连线的夹角给出,求面积
三角形面积公式,S=absinC/2,注意这里面给的是角度不是弧度。
#include
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const double PI = acos(-1.0);
const int M = 1e9+7;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
int n,d,a;
int main() {
//RE("in.txt");WR("out.txt");
while(~scanf("%d %d",&n,&d)) {
double ans=0;
for(int i=0;iscanf("%d",&a);
ans+=d*d*sin(a*1.0/180*PI)/2;
}
printf("%.3f\n",ans);
}
}
http://acm.hdu.edu.cn/showproblem.php?pid=5980
给你若干个32位无符号数,每个数分别表示为4个ascii码,问ascii码对应了几个’a’.
太水了,就是求每个数的256进制表示,有几位是97。
#include
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const double PI = acos(-1.0);
const int M = 1e9+7;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
int T;
ll a;
int main() {
scanf("%d",&T);
int cnt=0;
for(int t=1;t<=T;t++) {
scanf("%lld",&a);
while(a) {
if(a%256==97)
cnt++;
a/=256;
}
}
printf("%d\n",cnt);
}
据说这是个7题铜牌的时代,果然以我的理解力只能做出这7道了。还有道树状数组的题,和树分治,分分钟表示一脸懵逼.