CodeCraft-20 (Div. 2)
前言
比賽AC
簡明題意
有n個人,每個人有個分數,最高分是m。現在其中一個同學可以修改所有人的分數,他想使得最高分不超過m且平均分不變的情況下儘可能把自己分數修改高。問最高是多少。
正文
平均分不變,等價於總分不變。直接讓自己的分等於總分,其他人都0分就可以。然後和m比一下,如果比m大了就是m,否則就是總分。
代碼
簡明題意
有一個長度n<=5000的字符串,現在可以選一個k(1<=k<=n),選了k之後會依次反轉原字符串的1到k,2到k+1…最終得到新的字符串。問k選幾時,得到的新字符串字典序最小。
正文
k=2時,相當於冒泡排序,就是把a[1]移到了最後。
k>=2時,把1-k-1看成一個整體,這個整體會被移動到最後面。但注意每反轉一次,那個整體的順序就被顛倒一次。一共會被反轉n-k+1次,所以當n-k+1是奇數時,就應該反轉那個整體。
所以對於每個K就能O(1)得出操作後的字符串,而1<=k<=n,相當於一個字符串O(n)就能找到答案,複雜度是夠的。
代碼
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <string>
#include <vector>
using namespace std;
void solve ( )
{
int t;
cin >> t;
while ( t-- )
{
int n;
cin >> n;
string a;
cin >> a;
string ans;
int min_k;
for ( int k = 1 ; k <= n; k++ )
{
string x = a. substr ( 0 , k - 1 ) ;
if ( ( n - k + 1 ) % 2 == 1 ) reverse ( x. begin ( ) , x. end ( ) ) ;
string y = a. substr ( k - 1 , n - k + 1 ) ;
string b = y + x;
if ( ans == "" ) ans = b, min_k = k;
else if ( b < ans) ans = b, min_k = k;
}
cout << ans << endl;
cout << min_k << endl;
}
}
int main ( )
{
solve ( ) ;
return 0 ;
}
賽後補題
簡明題意
給你兩個多項式f(x)和g(x),用數組a[]給出f(x)的係數,b[]給出g(x)的係數。給出質數p,令h(x)=f(x)*g(x),現在需要你輸出h(x)的任意一個不能被p整除的係數。
a數組兩兩互質,b數組也是。
正文
首先得直到兩個多項式乘出來是什麼。假設有k和l,那麼
c x + y = ∏ i = 0 x + y a i b x + y = a 0 b x + y + a 1 b x + y − 1 + . . . + a x b y + . . . + a x + 1 b y − 1 + a x + y b 0 c_{x+y}=\prod_{i=0}^{x+y}a_ib_{x+y}=a_0b_{x+y}+a_1b_{x+y-1}+...+a_xb_y+...+a_{x+1}b_{y-1}+a_{x+y}b_0 c x + y = i = 0 ∏ x + y a i b x + y = a 0 b x + y + a 1 b x + y − 1 + . . . + a x b y + . . . + a x + 1 b y − 1 + a x + y b 0
現在想要找到不能被p整除的一個c。 既然不能被p整除,那就讓C x + y C_{x+y} C x + y 展開後的每一項都不能被p,可以嗎?不行。。。。因爲加起來後可能又能被p整除了。
通常做法是隻讓一項不能被p整除,其餘全讓他成爲p的倍數。這樣的話不能被p整除的項,就沒法加上一個數使得他能被p整除。現在,我們就想要c的展開式中,只有一項不能被p整除。
這裏可以讓a x a_x a x 和b y b_y b y 不能被p整除,其餘的a 1 到 a x − 1 a_1到a_{x-1} a 1 到 a x − 1 ,b 1 到 b x − 1 b_1到b_{x-1} b 1 到 b x − 1 全部能被p整除,這樣就會發現上面的展開式中,只有a x a y a_xa_y a x a y 這一項不能被p整除,其餘全部能被c整除。那麼就可以得出此時的c x + y c_x+y c x + y 能被p整除。
讓a x a_x a x 和b y b_y b y 不能被p整除,其餘的a 1 到 a x − 1 a_1到a_{x-1} a 1 到 a x − 1 ,b 1 到 b x − 1 b_1到b_{x-1} b 1 到 b x − 1 全部能被p整除。這個怎麼找呢?很簡單,直接遍歷ab數組,找到第一個不能被p整除的數字就可以了。
那麼我們現在思考一下ab數組分別互質的意義。目前爲止好像並沒有用到這個性質。
就是告訴你,ab數組不能全被p整除。因爲這樣的話就沒答案了
代碼
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1e5 + 10 ;
void solve ( )
{
int n, m, p;
cin >> n >> m >> p;
int x = - 1 , y = - 1 ;
for ( int i = 1 ; i <= n; i++ )
{
int t;
scanf ( "%d" , & t) ;
if ( x == - 1 && t % p != 0 )
{
x = i;
}
}
for ( int i = 1 ; i <= m; i++ )
{
int t;
scanf ( "%d" , & t) ;
if ( y == - 1 && t % p != 0 )
{
y = i;
break ;
}
}
cout << x + y - 2 ;
}
int main ( )
{
solve ( ) ;
return 0 ;
}
簡明題意
有一個n*n的矩陣。每個格子上有L、R、U、D、X五種字符,UDLR分別表示上下左右,X表示不走。
現在給出每個點作爲起點,最終的到達點。如果某點出發不會停下來,就是-1
正文
如果(x,y)到達(a,b),說明ab一定是X。並且可以知道,(x,y)到(a,b)路徑上的所有點,都應該是(a,b)。照這個思路,我們可以從(a,b)倒着搜回去,就能填好。那麼怎麼知道哪些點是X呢?直接判斷,如果有個點(x,y)==(a,b),那麼這個點就是X。
接下來只剩-1的沒填了。我們發現,對於-1的連通塊,只要連通塊內的點>=2個,我們可以把其中相鄰的兩個互相指向。然後其他所有的點指向這兩個點就可以了。
而實際上,我們可以發現,我們直接枚舉-1的點,只要他周圍存在一個-1,那麼直接指向就可以了。這樣就是對的。
現在說說答案不合法的情況。有兩種情況,會不合法。
1.一個點-1,與他相鄰的點卻沒有-1
2。例如,點1,1的值是1,3,但1,3卻是-1-1.
讀入不能用cin,否則tle
代碼
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1000 + 10 ;
const int dir[ 4 ] [ 2 ] = { 1 , 0 , 0 , 1 , - 1 , 0 , 0 , - 1 } ;
int n, gx[ maxn] [ maxn] , gy[ maxn] [ maxn] ;
char ans[ maxn] [ maxn] ;
int X_pos_x, X_pos_y;
void dfs ( int x, int y, char k)
{
ans[ x] [ y] = k;
for ( int z = 0 ; z < 4 ; z++ )
{
int tx = x + dir[ z] [ 0 ] , ty = y + dir[ z] [ 1 ] ;
if ( tx >= 0 && tx <= n && ty >= 0 && ty <= n && ans[ tx] [ ty] == 0 && gx[ tx] [ ty] == X_pos_x && gy[ tx] [ ty] == X_pos_y)
{
if ( z == 0 ) dfs ( tx, ty, 'U' ) ;
if ( z == 1 ) dfs ( tx, ty, 'L' ) ;
if ( z == 2 ) dfs ( tx, ty, 'D' ) ;
if ( z == 3 ) dfs ( tx, ty, 'R' ) ;
}
}
}
void solve ( )
{
cin >> n;
for ( int i = 1 ; i <= n; i++ )
for ( int j = 1 ; j <= n; j++ )
scanf ( "%d%d" , & gx[ i] [ j] , & gy[ i] [ j] ) ;
for ( int i = 1 ; i <= n; i++ )
for ( int j = 1 ; j <= n; j++ )
if ( i == gx[ i] [ j] && j == gy[ i] [ j] )
{
X_pos_x = i, X_pos_y = j;
dfs ( i, j, 'X' ) ;
}
for ( int i = 1 ; i <= n; i++ )
for ( int j = 1 ; j <= n; j++ )
if ( ans[ i] [ j] == 0 && gx[ i] [ j] == - 1 )
{
bool ok = 0 ;
int x = i, y = j;
for ( int z = 0 ; z < 4 ; z++ )
{
int tx = x + dir[ z] [ 0 ] , ty = y + dir[ z] [ 1 ] ;
if ( gx[ tx] [ ty] == - 1 )
{
if ( z == 0 ) ans[ x] [ y] = 'D' ;
if ( z == 1 ) ans[ x] [ y] = 'R' ;
if ( z == 2 ) ans[ x] [ y] = 'U' ;
if ( z == 3 ) ans[ x] [ y] = 'L' ;
ok = 1 ;
}
}
if ( ! ok)
{
cout << "INVALID" ;
return ;
}
}
for ( int i = 1 ; i <= n; i++ )
for ( int j = 1 ; j <= n; j++ )
if ( ans[ i] [ j] == 0 )
{
cout << "INVALID" ;
return ;
}
cout << "VALID" << endl;
for ( int i = 1 ; i <= n; i++ )
for ( int j = 1 ; j <= n; j++ )
{
printf ( "%c" , ans[ i] [ j] ) ;
if ( j == n) printf ( "\n" ) ;
}
}
int main ( )
{
solve ( ) ;
return 0 ;
}
簡明題意
共有n個人,現在從中選p個人作爲參賽選手,k個人作爲觀衆。
第i個人作爲參賽選手可以獲得a[i]分,第i個人作爲觀衆坐在第j個位置可以獲得s[i][j]分。現在需要你最大化這個得分。
正文
代碼
總結