Problem A. Built with Qinghuai and Ari Factor
水题就是看是不是所有数字都是3的倍数
Problem F. Color
容斥题,m个颜色里选k个,然后给一个长度n的路涂色,每格一个颜色,相邻不能相同,求方案数
ans=C(m,k)×(k(k−1)n−1−C(k,1)(k−1)(k−2)n−1+…)
为什么呢,假设k个条件,第i个条件是使用第i种颜色
然后我们开始容斥,首先什么条件都不要,然后减去有一种颜色不使用,加上有两种颜色不使用,这样
C(m,k)怎么算,k范围是100W,所以可以直接暴力算,1−100W的逆元都可以提前预处理
1−100W的阶乘的逆元也可以直接预处理,不然会TLE
代码:
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define MAX 1000005
#define MAXN 1000005
#define maxnode 15
#define sigma_size 30
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define middle int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem(x,v) memset(x,v,sizeof(x))
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define bits(a) __builtin_popcount(a)
#define mk make_pair
#define limit 10000
//const int prime = 999983;
const int INF = 0x3f3f3f3f;
const LL INFF = 0x3f3f;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-8;
const int mod = 1e9+7;
const ull mx = 133333331;
/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
LL fact[MAX];
LL ppow[MAX];
LL pp[MAX];
LL qpow(LL a,LL n){
LL ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
void init(){
fact[0]=1;
ppow[0]=qpow(fact[0],mod-2);
for(int i=1;i<=1000000;i++){
fact[i]=fact[i-1]*i%mod;
ppow[i]=qpow(fact[i],mod-2);
pp[i]=qpow(i,mod-2);
}
}
LL C(int n,int m){
return (fact[n]*ppow[m]%mod)*ppow[n-m]%mod;
}
int main(){
//freopen("in.out","r",stdin);
int t,kase=0;
cin>>t;
init();
while(t--){
kase++;
LL n,m,k;
cin>>n>>m>>k;
if(n==1&&k==1){
printf("Case #%d: ",kase);
cout<<m<<endl;
continue;
}
LL tmp=1;
for(int i=1;i<=k;i++){
tmp=(tmp*(m+1-i)%mod)*pp[i]%mod;
}
int flag=1;
LL ans=0;
for(int i=k;i>1;i--){
ans=ans+flag*(C(k,k-i)*i%mod)*qpow(i-1,n-1)%mod;
if(ans<0) ans+=mod;
if(ans>=mod) ans-=mod;
flag*=-1;
}
printf("Case #%d: ",kase);
cout<<ans*tmp%mod<<endl;
}
return 0;
}
Problem G. The Problem to Slow Down You
给你A,B两个字符串,然后问你有多少对四元组(a,b,c,d),Aa...b=Bc...d,并且Aa...b是回文
不懂字符串的其他算法,直接回文树上就行了
O(n)的处理A,B两个串,然后从0,1两个节点开始往下dfs,因为0,1两个节点是奇数偶数的起点
然后对于一个两个串里本质相同的节点,他们往下走相同字符得到的节点肯定也是本质相同
所以数量直接相乘即可
开头添加字符之后别忘记count,因为count之后,才是每个节点本质相同的个数都算完
代码:
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define MAX 200005
#define MAXN 1000005
#define maxnode 15
#define sigma_size 30
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define middle int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem(x,v) memset(x,v,sizeof(x))
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define bits(a) __builtin_popcount(a)
#define mk make_pair
#define limit 10000
//const int prime = 999983;
const int INF = 0x3f3f3f3f;
const LL INFF = 0x3f3f;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-8;
const int mod = 1e9+7;
const ull mx = 133333331;
/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
struct Palindromic_Tree {
int next[MAX][sigma_size] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
int fail[MAX] ;//fail指针,指向这个节点表示的回文串的最长后缀回文串的开头位置
int cnt[MAX] ;//这个节点上本质相同的回文串的个数(不完整,最后count之后才是每个节点上本质相同的回文串个数)
int num[MAX] ; //节点i表示的回文串的后缀回文串的个数
int len[MAX] ;//len[i]表示节点i表示的回文串的长度
int S[MAX] ;//存放添加的字符
int last ;//指向上一个字符所在的节点,方便下一次add
int n ;//字符数组指针
int p ;//节点指针
int newnode ( int l ) {//新建节点
for ( int i = 0 ; i < sigma_size ; ++ i ) next[p][i] = 0 ;
cnt[p] = 0 ;
num[p] = 0 ;
len[p] = l ;
return p ++ ;
}
void init () {//初始化
p = 0 ;
newnode ( 0 ) ;
newnode ( -1 ) ;
last = 0 ;
n = 0 ;
S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判
fail[0] = 1 ;
}
int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的
while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;
return x ;
}
void add ( char c ) {
c -= 'a' ;
S[++ n] = c ;
int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置
if ( !next[cur][c] ) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
int now = newnode ( len[cur] + 2 ) ;//新建节点
fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自动机一样建立fail指针,以便失配后跳转
next[cur][c] = now ;
num[now] = num[fail[now]] + 1 ;
}
last = next[cur][c] ;
cnt[last] ++ ;
}
void count () {
for ( int i = p - 1 ; i >= 0 ; -- i ) cnt[fail[i]] += cnt[i] ;
//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
}
}a,b;
char A[MAX],B[MAX];
LL dfs(int numa,int numb){
LL ans=0;
for(int i=0;i<26;i++){
if(a.next[numa][i]&&b.next[numb][i]){
ans+=(LL)a.cnt[a.next[numa][i]]*b.cnt[b.next[numb][i]]+dfs(a.next[numa][i],b.next[numb][i]);
}
}
return ans;
}
int main(){
//freopen("in.out","r",stdin);
int t,kase=0;
cin>>t;
while(t--){
kase++;
printf("Case #%d:\n",kase);
a.init();
b.init();
scanf("%s%s",A,B);
int lena=strlen(A);
int lenb=strlen(B);
for(int i=0;i<lena;i++) a.add(A[i]);
for(int i=0;i<lenb;i++) b.add(B[i]);
a.count();b.count();
cout<<dfs(0,0)+dfs(1,1)<<endl;
}
return 0;
}
Problem I. International Collegiate Routing Contest
题目哔哔了半天,其实就是给你一堆IP地址,然后问你求一些其他的IP地址
并起来和原来给的不想交并且互补
IP地址放成32位,然后根据子网掩码的长度,放进字典树L位
然后去字典树里dfs,如果碰到这个节点有,就往下dfs,如果空节点,就放进ans里
如果是终止节点,那么就return
最后化成十进制即可
代码:
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define MAX 30005
#define MAXN 1000005
#define maxnode 15
#define sigma_size 30
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define middle int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem(x,v) memset(x,v,sizeof(x))
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define bits(a) __builtin_popcount(a)
#define mk make_pair
#define limit 10000
//const int prime = 999983;
const int INF = 0x3f3f3f3f;
const LL INFF = 0x3f3f;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-8;
const int mod = 1e9+7;
const ull mx = 133333331;
/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
int ch[33*MAX][2];
int val[33*MAX];
int sz;
void init(){
mem(ch[0],0);
sz=1;
}
void inser(string a){
int u=0;
for(int i=0;i<a.size();i++){
int c=a[i]-'0';
if(!ch[u][c]){
mem(ch[sz],0);
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]=1;
}
vector<string> ans;
void query(int u,string s){
if(ch[u][0]&&!val[ch[u][0]]) query(ch[u][0],s+'0');
if(ch[u][1]&&!val[ch[u][1]]) query(ch[u][1],s+'1');
if(!ch[u][0]) ans.push_back(s+'0');
if(!ch[u][1]) ans.push_back(s+'1');
}
int main(){
//freopen("in.out","r",stdin);
int t,kase=0;
cin>>t;
while(t--){
kase++;
printf("Case #%d:\n",kase);
int n;
cin>>n;
ans.clear();
if(n==0){
printf("1\n");
printf("0.0.0.0/0\n");
continue;
}
init();
int a[5];
int flag=0;
for(int i=0;i<n;i++){
int l;
scanf("%d.%d.%d.%d/%d",&a[0],&a[1],&a[2],&a[3],&l);
if(l==0){
flag=1;
continue;
}
if(flag) continue;
string s="";
for(int j=0;j<4;j++){
string x="";
for(int k=0;k<8;k++){
char c=a[j]%2+'0';
x=c+x;
a[j]/=2;
}
s=s+x;
}
string tmp="";
for(int i=0;i<l;i++) tmp=tmp+s[i];
//cout<<tmp<<endl;
inser(tmp);
}
if(flag){
printf("0\n");
continue;
}
query(0,"");
printf("%d\n",(int)ans.size());
for(int i=0;i<ans.size();i++){
//cout<<ans[i]<<endl;
int l=ans[i].size();
for(int j=ans[i].size();j<32;j++) ans[i]=ans[i]+'0';
int tmp=0;
for(int j=0;j<8;j++){
tmp=tmp*2+(ans[i][j]-'0');
}
printf("%d.",tmp);
tmp=0;
for(int j=8;j<16;j++){
tmp=tmp*2+(ans[i][j]-'0');
}
printf("%d.",tmp);
tmp=0;
for(int j=16;j<24;j++){
tmp=tmp*2+(ans[i][j]-'0');
}
printf("%d.",tmp);
tmp=0;
for(int j=24;j<32;j++){
tmp=tmp*2+(ans[i][j]-'0');
}
printf("%d/%d\n",tmp,l);
}
}
return 0;
}
Problem K. Last Defence
S0=A
S1=B
Si=|Si−1−Si−2|fori≥2
开头没仔细考虑这题,以为很简单,其实仔细看,对于A,B两个数字,先会出现A,B辗转相除过程中出现的那些数字
然后是min(A,B)和辗转相除到最后的那个数字进行辗转相除
模拟一下辗转相除的过程即可
代码:
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define MAX 1000005
#define MAXN 1000005
#define maxnode 15
#define sigma_size 30
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define middle int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem(x,v) memset(x,v,sizeof(x))
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define bits(a) __builtin_popcount(a)
#define mk make_pair
#define limit 10000
//const int prime = 999983;
const int INF = 0x3f3f3f3f;
const LL INFF = 0x3f3f;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-8;
const int mod = 1e9+7;
const ull mx = 133333331;
/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
LL gcd(LL a,LL b){
if(!b) return a;
return gcd(b,a%b);
}
int main(){
//freopen("in.out","r",stdin);
int t,kase=0;
cin>>t;
while(t--){
LL a,b;
cin>>a>>b;
kase++;
printf("Case #%d: ",kase);
if(a==b){
if(a==0) cout<<1<<endl;
else cout<<2<<endl;
continue;
}
if(a<b) swap(a,b);
if(b==0){
cout<<2<<endl;
continue;
}
LL ans=2;
while(b!=0){
ans+=(a-b-1)/b;
a%=b;
swap(a,b);
ans++;
}
cout<<ans<<endl;
}
return 0;
}