這場題目挺水的。。感覺半小時能出3題。。可惜沒有注冊。。
B. Modulo Sum
題意:給100w個數,問是否存在子序列使得整個子序列的和能夠整除m。
思路:将所有數對m取模,然後問題就轉化成了一個多重背包問題,數比較多需要優化一下。不知道為什麼過的人這麼少。。
#include <cstdio>
#include <cstring>
int nums[100000], mod[3010], cnt;
bool dp[3010], dp2[3010];
main() {
int n, m;
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++) {
long long a;
scanf("%I64d", &a);
mod[a % m]++;
}
for(int i = 0; i < m; i++){
if(mod[i] == 0) continue;
int total = mod[i];
long long a = 1;
while(total >= a){
nums[cnt++] = (i * a) % m;
total -= a;
a <<= 1;
}
if(total > 0) nums[cnt++] = (i * total) % m;
}
for(int i = 0; i < cnt; i++){
memset(dp2, 0, sizeof dp2);
for(int j = 0; j < m; j++){
dp2[(j + nums[i]) % m] |= dp[j];
}
for(int j = 0; j < m; j++)
dp[j] |= dp2[j];
dp[nums[i]] = true;
}
if(dp[0]) puts("YES");
else puts("NO");
}
C. Vasya and Petya's Game
題意:兩個人玩遊戲,V君想一個1~n的整數,P君可以詢問V君這個數是否可以整除某個整數數K,詢問次數不限,問最少需要詢問多少次可以确定這個數。
思路:這題看樣例也能猜個差不多。。也很容易就能想到:任意一個大于等于2的自然數都是若幹質數的乘積,是以隻要詢問1~n範圍内所有的質數和質數的若幹次方能否被這個數整除就可以了。
#include <cstdio>
bool vis[1010], ans[1010];
int prim[1010], cnt;
main() {
int n;
scanf("%d", &n);
for(int i = 2; i <= n; i++){
if(vis[i] == false){
prim[cnt++] = i;
for(int j = i * i; j <= n; j += i) vis[j] = true;
}
}
int total = 0;
for(int i = 0; i < cnt; i++){
for(int j = prim[i]; j <= n; j *= prim[i])
ans[j] = true;
}
for(int i = 2; i <= n; i++) if(ans[i]) total++;
printf("%d\n", total);
for(int i = 2; i <= n; i++) if(ans[i]) printf("%d ", i);
}
D. Invariance of Tree
題意:給一個序列P1P2...Pn,若一棵樹上任意兩點u和v有一條邊相連,那麼這棵樹上Pu和Pv也有一條邊相連,問這棵樹是否存在,如果存在輸出任意一種樹的n-1條邊。
思路:這個題不是很有想法。。雖然想到找環但是沒有想清楚。。看了tutorial才明白:
這些數字可以分成若幹組,每組都會形成一個互不相交的環(集合), 可以通過i=Pi遞歸找到每個環。
讓所有環和一個”中心環“建邊(可以把環想成點),這樣就形成了一棵樹,也不會再次構成環。
但是在建邊的時候邊需要錯開,這樣其他環的點的個數必須是中心環的整數倍(畫個圖就很容易想明白)。
因為其他所有環都要和中心環相連構成樹,是以中心環内的點之間需要建邊構成樹。
而中心環的點要循環和其他環建邊,是以中心環的點的個數要少于3個(大于等于3個的時候就會形成環)。
這樣我們就需要做這幾件事情:
1.尋找環内點個數為1或2的環作為“中心環”,沒有則不能成樹;
2.如果中心環點數為1,那麼一定可以成樹,讓這個點和其他各點建邊即可;
如果中心環點數為2,那麼其他環的點的個數必須是偶數,否則不能成樹,然後中心環兩點循環與其他環建邊,中心環兩點間也要建邊。
#include <cstdio>
#include <vector>
using namespace std;
vector<int>link[100020];
bool vis[100020];
int p[100020];
main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
int one = 0, two = 0;
for(int i = 1; i <= n; i++){
if(vis[i]) continue;
int v = i;
while(!vis[v]){
link[i].push_back(v);
vis[v] = true;
v = p[v];
}
if(link[i].size() == 1) one = i;
else if(link[i].size() == 2) two = i;
}
if(one){
puts("YES");
for(int i = 1; i <= n; i++){
if(i != one) printf("%d %d\n", one, i);
}
}
else if(two){
bool flag = true;
for(int i = 1; i <= n; i++)
if(link[i].size() % 2)
flag = false;
if(!flag) puts("NO");
else {
puts("YES");
printf("%d %d\n", link[two][0], link[two][1]);
for(int i = 1; i <= n; i++){
if(two != i){
for(int j = 0; j < link[i].size(); j++)
printf("%d %d\n", link[two][j & 1], link[i][j]);
}
}
}
}
else puts("NO");
}