比赛链接
题目链接
Daniel is organizing a football tournament. He has come up with the following tournament format:
In the first several (possibly zero) stages, while the number of teams is even, they split in pairs and play one game for each pair. At each stage the loser of each pair is eliminated (there are no draws). Such stages are held while the number of teams is even.
Eventually there will be an odd number of teams remaining. If there is one team remaining, it will be declared the winner, and the tournament ends. Otherwise each of the remaining teams will play with each other remaining team once in round robin tournament (if there are x teams, there will be games), and the tournament ends.
For example, if there were 20 teams initially, they would begin by playing 10 games. So, 10 teams would be eliminated, and the remaining 10 would play 5 games. Then the remaining 5 teams would play 10 games in a round robin tournament. In total there would be 10+5+10=25 games.
Daniel has already booked the stadium for n games. Help him to determine how many teams he should invite so that the tournament needs exactly n games. You should print all possible numbers of teams that will yield exactly n games in ascending order, or -1 if there are no such numbers.
The first line contains a single integer n (1 ≤ n ≤ 1018), the number of games that should be played.
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.
Print all possible numbers of invited teams in ascending order, one per line. If exactly n games cannot be played, output one number: -1.
3
3
4
25
20
2
-1
设最后得到一个奇数 m m m ,最开始的人数为 2 p × m 2^p\times m 2p×m。则一共进行的比赛数 m × ( m − 1 ) 2 + ( 2 p − 1 ) × m = n \frac{m\times (m-1)}{2}+(2^p-1)\times m=n 2m×(m−1)+(2p−1)×m=n。此方程有两个未知量,可以枚举 p p p 二分查找 m m m。
#include
#include
#include
using namespace std;
typedef long long ll;
const ll INF=15e8;
ll n;
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
bool find=false;ll c,i;
for(i=0;(c=(1ll<
通过枚举范围小的未知量来解方程。要注意二分的上下界,上限开大了会爆long long,开小了也会跪,开到 15 e 8 15e8 15e8 差不多。
题目链接
Some days ago, I learned the concept of LCM (least common multiple). I’ve played with it for several times and I want to make a big number with it.
But I also don’t want to use many numbers, so I’ll choose three positive integers (they don’t have to be distinct) which are not greater than n. Can you help me to find the maximum possible least common multiple of these three integers?
The first line contains an integer n (1 ≤ n ≤ 106) — the n mentioned in the statement.
Print a single integer — the maximum possible LCM of three not necessarily distinct positive integers that are not greater than n.
9
504
7
210
The least common multiple of some positive integers is the least positive integer which is multiple for each of them.
The result may become very large, 32-bit integer won’t be enough. So using 64-bit integers is recommended.
For the last example, we can chose numbers 7, 6, 5 and the LCM of them is 7·6·5 = 210. It is the maximum value we can get.
大佬的解法非常巧妙,摘抄如下:
题目大意:求不超过n的三个数的最大公倍数。
分析:首先要知道两个数论性质:1、相邻两个整数互质。2、相邻两个奇数互质。
然后,小数据观察规律,按 n n n 的奇偶性讨论。
一、 n n n 为奇数时, n − 2 n-2 n−2 必定为奇数,而 n − 1 n-1 n−1 与它俩都相邻,因此,两两互质。最大公倍数即为 n ∗ ( n − 1 ) ∗ ( n − 2 ) n*(n-1)*(n-2) n∗(n−1)∗(n−2)。
二、 n n n 为偶数时,由于 n n n 与 n − 2 n-2 n−2 均为偶数,所以,退而求其次,选择 n − 3 n-3 n−3 。又 n n n 与 n − 3 n-3 n−3 是否互质,衍生出两种情况:
1、 n n n 为 3 3 3 的倍数,则 n n n 与 n − 3 n-3 n−3 不互质,然而, n n n 与 n − 4 n-4 n−4 不互质,所以,此时,不选择 n n n,改为选 n − 2 n-2 n−2。最后, L C M = ( n − 1 ) ∗ ( n − 2 ) ∗ ( n − 3 ) LCM = (n-1)*(n-2)*(n-3) LCM=(n−1)∗(n−2)∗(n−3)
2、 n n n不为 3 3 3 的倍数,则 n n n 与 n − 3 n-3 n−3 互质,所以, L C M = n ∗ ( n − 1 ) ∗ ( n − 3 ) LCM = n*(n-1)*(n-3) LCM=n∗(n−1)∗(n−3)
#include
typedef long long ll;
int main()
{
ll n;
scanf("%lld",&n);
if(n==1)puts("1");
else if(n==2)puts("2");
else if(n&1)printf("%lld\n",n*(n-1)*(n-2));
else if(n%3==0)printf("%lld\n",(n-1)*(n-2)*(n-3));
else printf("%lld\n",n*(n-1)*(n-3));
return 0;
}
数学是一生之敌。巧妙利用互质的性质。
题目链接
Yaroslav, Andrey and Roman can play cubes for hours and hours. But the game is for three, so when Roman doesn’t show up, Yaroslav and Andrey play another game.
Roman leaves a word for each of them. Each word consists of 2·n binary characters “0” or “1”. After that the players start moving in turns. Yaroslav moves first. During a move, a player must choose an integer from 1 to 2·n, which hasn’t been chosen by anybody up to that moment. Then the player takes a piece of paper and writes out the corresponding character from his string.
Let’s represent Yaroslav’s word as s = s1s2… s2n. Similarly, let’s represent Andrey’s word as t = t1t2… t2n. Then, if Yaroslav choose number k during his move, then he is going to write out character sk on the piece of paper. Similarly, if Andrey choose number r during his move, then he is going to write out character tr on the piece of paper.
The game finishes when no player can make a move. After the game is over, Yaroslav makes some integer from the characters written on his piece of paper (Yaroslav can arrange these characters as he wants). Andrey does the same. The resulting numbers can contain leading zeroes. The person with the largest number wins. If the numbers are equal, the game ends with a draw.
You are given two strings s and t. Determine the outcome of the game provided that Yaroslav and Andrey play optimally well.
The first line contains integer n (1 ≤ n ≤ 106). The second line contains string s — Yaroslav’s word. The third line contains string t — Andrey’s word.
It is guaranteed that both words consist of 2·n characters “0” and “1”.
Print “First”, if both players play optimally well and Yaroslav wins. If Andrey wins, print “Second” and if the game ends with a draw, print “Draw”. Print the words without the quotes.
2
0111
0001
First
3
110110
001001
First
3
111000
000111
Draw
4
01010110
00101101
First
4
01100000
10010011
Second
优先选择双方都为1的,次选己方为1,次选对方为1。
#include
#include
using namespace std;
string s,t;
int n,cnts,cntt,cntd;
int main()
{
//freopen("in.txt","r",stdin);
cin>>n;n*=2;
cin>>s>>t;
for(int i=0;icntt)puts("First");
else if(cnts
博弈论初步
题目链接
You have a rectangular n × m-cell board. Some cells are already painted some of k colors. You need to paint each uncolored cell one of the k colors so that any path from the upper left square to the lower right one doesn’t contain any two cells of the same color. The path can go only along side-adjacent cells and can only go down or right.
Print the number of possible paintings modulo 1000000007 (109 + 7).
The first line contains three integers n, m, k (1 ≤ n, m ≤ 1000, 1 ≤ k ≤ 10). The next n lines contain m integers each — the board. The first of them contains m uppermost cells of the board from the left to the right and the second one contains m cells from the second uppermost row and so on. If a number in a line equals 0, then the corresponding cell isn’t painted. Otherwise, this number represents the initial color of the board cell — an integer from 1 to k.
Consider all colors numbered from 1 to k in some manner.
Print the number of possible paintings modulo 1000000007 (109 + 7).
2 2 4
0 0
0 0
48
2 2 4
1 2
2 1
0
5 6 10
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
3628800
2 6 10
1 2 3 4 5 6
0 0 0 0 0 0
4096
大佬题解写的非常好,摘抄如下:
题目大意:
给出一个n*m的矩阵,其中一些格子填了数,一些格子没有。现要求将未填数的格子填上数字,使得矩阵从左上到右下(不允许向左或上走)的任意一条路径上没有两个格子数字相同,数字范围为1~K。 1<=n,m<=1000,1<=k<=10
分析:
首先一看,在(n+m-1)大于K时必定无解,这样就把n,m范围缩小到了10以内。
我们考虑搜索解决。但是纯暴搜时间不够,可以用两个剪枝优化:
(1)可行性剪枝,如果在当前格子填数时,剩下的颜色已经不够用则直接回溯。
(2)对称性剪枝:例如我们当前填到了某个格子,我们记录一下整个矩阵已使用的颜色,例如3,5都还没用,那么这个格子填上3或5,两者最终算出的方案数是相同的,这样我们就可以只计算3的方案数,5的直接加上3的就可以了。
#include
typedef long long ll;
const int mod=1e9+7;
int n,m,k,vis[11],a[11][11],f[11][11];//f[x][y]记录每个阶段颜色的使用情况
ll ans;
void dfs(int x,int y)
{
if(x==n+1)
{
if(++ans==mod)ans=0;
return;
}
f[x][y]=f[x-1][y]|f[x][y-1];
int cnt=0,p=1,q=k;ll sum=-1,pre;
for(int i=1;i<=k;i++)if((f[x][y]&(1<<(i-1)))!=0)cnt++;//已用颜色数
if(n-x+m-y+1>k-cnt)return;//可行性剪枝
if(a[x][y]>0)p=q=a[x][y];
for(int i=p;i<=q;i++)
if((f[x][y]&(1<<(i-1)))==0)//当前状态没用过这种颜色
{
if(!vis[i])//这个颜色没出现过
{
if(sum>=0)//对称性剪枝,如果sum>=0说明该位的颜色是没出现过的,且已经考虑过
{
ans+=sum;
if(ans>=mod)ans-=mod;
continue;
}
pre=ans;
}
f[x][y]^=(1<<(i-1)),vis[i]++;
if(y==m)dfs(x+1,1);else dfs(x,y+1);
f[x][y]^=(1<<(i-1)),vis[i]--;
if(!vis[i])sum=(ans-pre)%mod;//对于没用过的颜色,得到的sum是相等的
}
}
int main()
{
//freopen("in.txt","r",stdin);;
scanf("%d%d%d",&n,&m,&k);
if(n+m-1>k)
{
puts("0");return 0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]>0)vis[a[i][j]]++;//记录颜色出现数
}
dfs(1,1);
printf("%lld\n",ans);
return 0;
}
果然爆搜才是男人的浪漫。
其实也不算比赛,就只是做练习题。考的还是一些算法难度不大但比较考思维的东东,不错。