轉戰Atcoder,這場比賽的名字看起來就很有趣的樣子,很盛大的感覺,那當然趕緊來玩玩
A - Takahashi Calendar
思路:定義新日曆算法,求特定日子數
典型的簽到題,當然是直接在新日曆上跑一遍即可
#include <bits/stdc++.h>
using namespace std;
int main()
{
int mm,dd;
scanf("%d%d",&mm,&dd);
int sum = 0;
for(int m=1;m<=mm;m++)
{
for(int d=1;d<=dd;d++)
{
int d1 = d%10;
int d10 = d/10;
if(d1>=2&&d10>=2&&d1*d10==m)
sum++;
}
}
printf("%d\n",sum);
return 0;
}
B - Kleene Inversion
思路:看似一個很複雜的逆序對問題,立刻想着像逆序對上套,實則不然,由於子串長度過短,完全可以直接暴力預處理掉子串,處理掉該串中的大小和該位置後的大小,最後只是個小小數學計算問題了。而對於大數帶模除法,直接一個逆元搞定
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3+5;
const ll mod = (ll)(1e9+7);
int aa[maxn],rk[maxn],ne[maxn];
ll gcd(ll a,ll b, ll &x,ll &y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
else
{
ll r = gcd(b,a%b,y,x);
y -= x * (a / b);
return r;
}
}
ll ni(ll a,ll n)
{
ll x, y;
ll d = gcd(a, n, x, y);
ll ans;
if(d == 1)
{
x %= n;
x += n;
x %= n;
ans = (x % n);
return ans;
}
else
{
return -1;
}
}
int main()
{
int n,k;
ll b=0LL;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d",&aa[i]);
rk[i] = 0;
ne[i] = 0;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<i;j++)
{
if(aa[i]>aa[j])
rk[i]++;
}
for(int j=i;j<n;j++)
{
if(aa[i]>aa[j])
{
ne[i]++;
rk[i]++;
}
}
b = (b + (((((((ll)rk[i]*(ll)(k-1))%mod)*(ll)k)%mod)*ni(2,mod))%mod) + (((ll)ne[i] * (ll)k)%mod)) % mod;
}
printf("%lld\n",b);
return 0;
}
C - Cell Inversion
思路:翻轉序列題,也是個看似很困難的題,但細心品味也確實是一道很有意思的題目
首先,題目中明確說明了每個點都必須翻轉一次,這就意味着必會存在n組翻轉組合,問題的關鍵就是找出個n種組合方式,至於組合之間的順序並不重要
於是二話不說,先來個關於n的全排列。
接下來,由於序列翻轉的核心就在元素變換交叉處。
不難發現,這題可以轉化爲將變換端點視爲括號的括號匹配題,由於每個點比對應一個括號,則相鄰兩個括號之間的關係將成爲關鍵。
若相鄰兩個點均爲左括號或均爲右括號,由於外側點多進行了一次變換,導致這兩點必然不同;相應若相鄰兩點括號相同,則剛好形成一種無縫連接,使得變換結果必相同。
當然,一旦確定了每個點所屬的變換類型,相應的對應匹配對也不重要了,因爲只要能滿足括號匹配規則(允許括號交叉,不允許右括號先於左括號),匹配出來的結果必能相同。
這樣算來,只需要計算每次右括號出現時前面已出現的左括號數量,作爲方案數,並任意消耗一個左括號進行匹配
最後,就可以根據相鄰點間的元素關係預處理各個點的變換類型,然後再遍歷計算方案數即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
const ll mod = ll(1e9+7);
char s[maxn];
int s2[maxn];
int main()
{
int n;
scanf("%d%s",&n,s);
s2[0] = 1;
for(int i=1;i<2*n;i++)
{
if(s[i]==s[i-1])
s2[i] = (s2[i-1]+1)%2;
else
s2[i] = s2[i-1];
}
ll sum = 1LL;
for(int i=2;i<=n;i++)
{
sum = (sum * (ll)i)%mod;
}
//cout << sum << endl;
int num = 0;
for(int i=0;i<2*n;i++)
{
//out << sum << "*" << num << endl;
if(s2[i]==1)
num++;
else
{
sum = (sum * ll(num))%mod;
//cout << sum << "*" << num << endl;
num--;
}
}
if(s[0]=='W'||num!=0)
printf("0\n");
else
printf("%lld\n",sum);
return 0;
}