A. Good ol’ Numbers Coloring
判斷2個數是否互質就行了
AC代碼
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
const ll mod = 1e9+7;
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t;cin >> t;
while(t--){
int a,b;
cin >> a>> b;
if(gcd(a,b)!=1)cout << "Infinite" << endl;
else cout << "Finite" <<endl;
}
return 0;
}
B. Restricted RPS
題意:石頭剪刀布的規則,給你一個字符串只包含‘R’,‘P’,'S’三種字符,
R:石頭 P:布 S:剪刀
然後有a個石頭,b個布,c個剪刀
讓你贏的局數大於等於ceil(n/2)(向上取整)
思路:一次匹配,有能贏的就贏,不能贏的先放着不管,最後在把剩餘的隨便分給先前沒管的。
AC代碼
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
const ll mod = 1e9+7;
map<char,int>mp;
map<char,char>dui;
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t;cin >>t;
dui['R'] = 'P';dui['P'] = 'S';dui['S'] = 'R';
while(t--){
int n;cin >> n;
int a,b,c;
cin >> a>> b >> c;
mp['R'] = a;mp['P'] = b;mp['S'] = c;
string s;cin >> s;
int ans = 0;
char res[110];
memset(res,0,sizeof(res));//注意每次對res清零,無腦貢獻2發罰時.
for(int i = 0;i < s.size();i++){
if(mp[dui[s[i]]]>0){
ans++;
mp[dui[s[i]]]--;
res[i] = dui[s[i]];
}
}
for(int i = 0;i < n;i++){
if(res[i]!='R'&&res[i]!='S'&&res[i]!='P'){
if(mp['S']>0)res[i] = 'S',mp['S']--;
else if(mp['R']>0)res[i] = 'R',mp['R']--;
else if(mp['P']>0)res[i] = 'P',mp['P']--;
}
}
res[n] = '\0';
n = ceil(1.0*n/2);
if(ans>=n)cout << "YES\n",cout << res << endl;
else cout << "NO\n";
}
return 0;
}
C. Constanze’s Machine
題意:原序列中的m會變成nn,w會變成vv;形成最終序列
現在給你最終序列,求原序列有多少種。
思路:首先要組成m或w,肯定要連續的nn或vv,那我們就來看長度爲n的vv有多少種情況。
考慮dp,dp[i]表示前i個位置的組合情況,對於當前位置,要麼自己單獨,要麼與前一個n組成一個m,所以dp[i] = dp[i-1] + dp[i-2] 。dp[0] = 1,dp[1] = 1;
(其實列舉幾個出來就會發現就是一個fib數列)
每段連續的求出來了,乘起來就是答案,注意取模.
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
const ll mod = 1e9+7;
int dp[man];
void init(int n){
dp[1] = dp[0] = 1;
for(int i = 2;i <= n;i++){
dp[i] = (dp[i-1] + dp[i-2])%mod;
}
}
vector<int>res;
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
string s;
cin >> s;
init(s.size());
int len = s.size();
bool f = 0;
for(int i = 0;i < len;i++){
if(s[i]=='w'||s[i]=='m')f = 1;
if(s[i]=='u'||s[i]=='n'){
int le = 1;int j;
for(j = i+1;j < len;j++){
if(s[j]==s[i])le++;
else break;
}
i = j-1;
res.push_back(le);
}
}
if(f)cout << "0" << endl;
else{
ll ans = 1;
for(int i = 0;i < res.size();i++){
ans = (ans*dp[res[i]])%mod;
}
cout << ans << endl;
}
return 0;
}
D. Shichikuji and Power Grid
題意:n個笛卡爾座標上的點,每個點有一個ci,ki,現在需要全部點通電,可以在該點建發電站,也可以連接其他發電站,在每個點建發電站的花費爲ci,連接其他點的花費爲兩點的曼哈頓距離*兩點k之和。求花費最小。
思路:建圖,跑最小生成樹。爲什麼這樣做?首先我們每個點都要通電且花費最小,很明顯最小生成樹。
建圖:一個超級源點連接n個點,邊權爲ci,表示這個點是否做發電站,然後每個點與其他點連一條邊,權值爲連接邊的花費。
用prime算法跑生成樹,結構體記錄當前點的前驅結點,用來保存答案
AC代碼
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e3+10;
#define IOS ios::sync_with_stdio(0)
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef long long ll;
ll inf = 1e18;
const ll mod = 1e9+7;
struct node{
int x,y;
int c,k;
}a[man];
struct noe{
int u;
ll dis;
};
struct no{
int u,pre;
ll dis;
bool operator <(const no &a)const{
return dis > a.dis;
}
};
vector<noe>sp[man];
ll dis[man];
bool vis[man];
priority_queue<no>q;
vector<pair<int,int> >res2;
vector<int>res1;
int n;
void prim(int s){
for(int i = s;i <= n;i++)dis[i] = inf;
memset(vis,false,sizeof(vis));
q.push(no{s,-1,0});
ll ans = 0;
while(!q.empty()){
no tp = q.top();q.pop();
int u = tp.u;
if(vis[u])continue;
vis[u] = 1;
ans += tp.dis;
if(tp.dis!=0){
if(tp.pre==0)res1.push_back(u);
else res2.push_back(make_pair(u,tp.pre));
}
for(int i = 0;i < sp[u].size();i++){
int v = sp[u][i].u;
ll diss = sp[u][i].dis;
if(vis[v])continue;
if(dis[v] > diss){
dis[v] = diss;
q.push(no{v,u,dis[v]});
}
}
}
cout << ans << endl;
cout << res1.size() << endl;
for(int i = 0;i < res1.size();i++){
cout << res1[i] << " " ;
}cout <<endl;
cout << res2.size() << endl;
for(int i = 0;i < res2.size();i++){
cout << res2[i].first << " " << res2[i].second <<endl;
}
}
signed main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
cin >> n;
for(int i = 1;i <= n;i++)cin >> a[i].x >> a[i].y;
for(int i = 1;i <= n;i++)cin >> a[i].c;
for(int i = 1;i <= n;i++)cin >> a[i].k;
int s = 0;
for(int i = 1;i <= n;i++){
sp[s].push_back(noe{i,a[i].c});
sp[i].push_back(noe{s,a[i].c});
}
for(int i = 1;i <= n;i++){
for(int j = i + 1;j <= n;j++){
ll dis = abs(a[i].x-a[j].x) + abs(a[i].y-a[j].y);
sp[i].push_back(noe{j,1ll*dis*(a[i].k + a[j].k)});
sp[j].push_back(noe{i,1ll*dis*(a[i].k + a[j].k)});
}
}
prim(s);
return 0;
}
E:
題意:給你一個10*10的網格,要你從左下角走到左上角,奇數行只能向右走,偶數行向左走,遇到邊界就向上。
每次的走的步數是由投擲骰子決定的,6種可能,概率相同,還有直達的,就是向上x行,但不能2次都連續2次直達,
問最少步數。
思路:很明顯的一個期望dp,比賽時時間不夠(還是太菜),考慮把二維格子想成一條直線,然後樓梯關係對應一下,
dp[i]表示離終點的最小期望步數,dp[100] = 0,
對於94-99情況比較特殊,因爲會有自環,
dp[i] = (dp[i]+1)*5/6 + (dp[100] + 1)/ 6 ⇒ dp[i] = 6
對於後面的,有2種決策,搭樓梯 or 投骰子 之間取一個min就好
java代碼
import java.util.*;
import java.io.*;
public class Main{
static double dp[];
public static void main(String argv[]) throws IOException {
StreamTokenizer in = new StreamTokenizer(
new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int id[][] = new int[15][15];
int t[] = new int[110];
int num = 100;
dp = new double[110];
for(int i = 1;i <= 10;i++) {
int tp,p;
if(i%2==0) {
tp = 10;p = -1;
}else {
tp = 1;p = 1;
}
for(int j = 1;j <= 10;j++) {
id[i][tp] = num--;
tp += p;
}
}
/*for(int i = 1;i <= 10;i++) {
for(int j = 1;j <= 10;j++) {
out.printf("%d ", id[i][j]);
}
out.printf("\n");
}*/
Arrays.fill(t, 0);
for(int i = 1;i <= 10;i++) {
for(int j = 1;j <= 10;j++) {
int x;in.nextToken();
x = (int)in.nval;
t[id[i][j]] = id[i-x][j];
//out.printf("%d ",t[id[i][j]]);
}
//out.printf("\n");
}
dp[100] = 0.0;
for(int i = 99;i >= 94;i--)dp[i] = 6.0;
for(int i = 93;i >= 1;i--) {
double ans = 0;
for(int j = 1;j <= 6;j++) {
ans += Math.min((dp[i+j]+1)/6.0,(1+dp[t[i+j]])/6.0);
}
dp[i] = ans;
}
out.printf("%.10f\n", dp[1]);
out.close();
}
}
F:
題意:一個區間[l,r],問你這個區間有多少對數滿足x + y = x ^ y ;
思路:很明顯每位取的情況只有3種,{0 ,1} {1 ,0 } {0 ,0 }
先轉化爲2進制
考慮dp[i][][]表示前i位數x,y是否達到上限的組合數;
import java.util.*;
import java.io.*;
public class Main{
static final int man = 35+10;
static long dp[][][];
static int x[],y[];
public static void main(String argv[]) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int t;
in.nextToken();
t = (int)in.nval;
while(t-->0) {
int l,r;
in.nextToken();
l = (int)in.nval;
in.nextToken();
r = (int)in.nval;
long ans = slove(r,r) - slove(l-1,r) - slove(r,l-1) + slove(l-1,l-1);
out.println(ans);
out.flush();
}
out.close();
}
static long slove(int a,int b) {
if(a<0||b<0)return 0;
int pos = 0;
dp = new long[50][2][2];
x = new int[50];
y = new int[50];
for(int i = 0;i < 35;i++) {
for(int j = 0;j < 2;j++) {
for(int k = 0;k < 2;k++) {
dp[i][j][k] = -1;
//System.out.println(i + " " + j + " " + k);
}
}
}
while(a!=0||b!=0) {
//System.out.println(pos + " " + a + " " + b);
x[++pos] = a&1;
y[pos] = b&1;
a /= 2;
b /= 2;
}
return dfs(pos,1,1);
}
static long dfs(int pos,int t1,int t2) {
if(pos==0)return 1;
if(dp[pos][t1][t2] != -1)return dp[pos][t1][t2];
long ans = 0;
int up1 = t1==1 ? x[pos] : 1;
int up2 = t2==1 ? y[pos] : 1;
for(int i = 0;i <= up1;i++) {
for(int j = 0;j <= up2;j++) {
if(i==1&&j==1) continue;
int a1 = 0,b1 = 0;
if(t1==1&&i==up1)a1 = 1;
if(t2==1&&j==up2)b1 = 1;
ans += dfs(pos-1,a1,b1);
}
}
dp[pos][t1][t2] = ans;
return ans;
}
}